qywechat.class.php 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070
  1. <?php
  2. /**
  3. * 微信公众平台企业号PHP-SDK, 官方API类库
  4. * @author binsee <binsee@163.com>
  5. * @link https://github.com/binsee/wechat-php-sdk
  6. * @version 1.0
  7. * usage:
  8. * $options = array(
  9. * 'token'=>'tokenaccesskey', //填写应用接口的Token
  10. * 'encodingaeskey'=>'encodingaeskey', //填写加密用的EncodingAESKey
  11. * 'appid'=>'wxdk1234567890', //填写高级调用功能的app id
  12. * 'appsecret'=>'xxxxxxxxxxxxxxxxxxx', //填写高级调用功能的密钥
  13. * 'agentid'=>'1', //应用的id
  14. * 'debug'=>false, //调试开关
  15. * '_logcallback'=>'logg', //调试输出方法,需要有一个string类型的参数
  16. * );
  17. *
  18. */
  19. class Wechat
  20. {
  21. const MSGTYPE_TEXT = 'text';
  22. const MSGTYPE_IMAGE = 'image';
  23. const MSGTYPE_LOCATION = 'location';
  24. const MSGTYPE_LINK = 'link'; //暂不支持
  25. const MSGTYPE_EVENT = 'event';
  26. const MSGTYPE_MUSIC = 'music'; //暂不支持
  27. const MSGTYPE_NEWS = 'news';
  28. const MSGTYPE_VOICE = 'voice';
  29. const MSGTYPE_VIDEO = 'video';
  30. const EVENT_SUBSCRIBE = 'subscribe'; //订阅
  31. const EVENT_UNSUBSCRIBE = 'unsubscribe'; //取消订阅
  32. const EVENT_LOCATION = 'LOCATION'; //上报地理位置
  33. const EVENT_ENTER_AGENT = 'enter_agent'; //用户进入应用
  34. const EVENT_MENU_VIEW = 'VIEW'; //菜单 - 点击菜单跳转链接
  35. const EVENT_MENU_CLICK = 'CLICK'; //菜单 - 点击菜单拉取消息
  36. const EVENT_MENU_SCAN_PUSH = 'scancode_push'; //菜单 - 扫码推事件(客户端跳URL)
  37. const EVENT_MENU_SCAN_WAITMSG = 'scancode_waitmsg'; //菜单 - 扫码推事件(客户端不跳URL)
  38. const EVENT_MENU_PIC_SYS = 'pic_sysphoto'; //菜单 - 弹出系统拍照发图
  39. const EVENT_MENU_PIC_PHOTO = 'pic_photo_or_album'; //菜单 - 弹出拍照或者相册发图
  40. const EVENT_MENU_PIC_WEIXIN = 'pic_weixin'; //菜单 - 弹出微信相册发图器
  41. const EVENT_MENU_LOCATION = 'location_select'; //菜单 - 弹出地理位置选择器
  42. const EVENT_SEND_MASS = 'MASSSENDJOBFINISH'; //发送结果 - 高级群发完成
  43. const EVENT_SEND_TEMPLATE = 'TEMPLATESENDJOBFINISH';//发送结果 - 模板消息发送结果
  44. const API_URL_PREFIX = 'https://qyapi.weixin.qq.com/cgi-bin';
  45. const USER_CREATE_URL = '/user/create?';
  46. const USER_UPDATE_URL = '/user/update?';
  47. const USER_DELETE_URL = '/user/delete?';
  48. const USER_BATCHDELETE_URL = '/user/batchdelete?';
  49. const USER_GET_URL = '/user/get?';
  50. const USER_LIST_URL = '/user/simplelist?';
  51. const USER_LIST_INFO_URL = '/user/list?';
  52. const USER_GETINFO_URL = '/user/getuserinfo?';
  53. const USER_INVITE_URL = 'invite/send?';
  54. const DEPARTMENT_CREATE_URL = '/department/create?';
  55. const DEPARTMENT_UPDATE_URL = '/department/update?';
  56. const DEPARTMENT_DELETE_URL = '/department/delete?';
  57. const DEPARTMENT_MOVE_URL = '/department/move?';
  58. const DEPARTMENT_LIST_URL = '/department/list?';
  59. const TAG_CREATE_URL = '/tag/create?';
  60. const TAG_UPDATE_URL = '/tag/update?';
  61. const TAG_DELETE_URL = '/tag/delete?';
  62. const TAG_GET_URL = '/tag/get?';
  63. const TAG_ADDUSER_URL = '/tag/addtagusers?';
  64. const TAG_DELUSER_URL = '/tag/deltagusers?';
  65. const TAG_LIST_URL = '/tag/list?';
  66. const MEDIA_UPLOAD_URL = '/media/upload?';
  67. const MEDIA_GET_URL = '/media/get?';
  68. const AUTHSUCC_URL = '/user/authsucc?';
  69. const MASS_SEND_URL = '/message/send?';
  70. const MENU_CREATE_URL = '/menu/create?';
  71. const MENU_GET_URL = '/menu/get?';
  72. const MENU_DELETE_URL = '/menu/delete?';
  73. const TOKEN_GET_URL = '/gettoken?';
  74. const CALLBACKSERVER_GET_URL = '/getcallbackip?';
  75. const OAUTH_PREFIX = 'https://open.weixin.qq.com/connect/oauth2';
  76. const OAUTH_AUTHORIZE_URL = '/authorize?';
  77. private $token;
  78. private $encodingAesKey;
  79. private $appid; //也就是企业号的CorpID
  80. private $appsecret;
  81. private $access_token;
  82. private $agentid; //应用id AgentID
  83. private $postxml;
  84. private $agentidxml; //接收的应用id AgentID
  85. private $_msg;
  86. private $_receive;
  87. private $_sendmsg; //主动发送消息的内容
  88. private $_text_filter = true;
  89. public $debug = false;
  90. public $errCode = 40001;
  91. public $errMsg = "no access";
  92. private $_logcallback;
  93. public function __construct($options)
  94. {
  95. $this->token = isset($options['token'])?$options['token']:'';
  96. $this->encodingAesKey = isset($options['encodingaeskey'])?$options['encodingaeskey']:'';
  97. $this->appid = isset($options['appid'])?$options['appid']:'';
  98. $this->appsecret = isset($options['appsecret'])?$options['appsecret']:'';
  99. $this->agentid = isset($options['agentid'])?$options['agentid']:'';
  100. $this->debug = isset($options['debug'])?$options['debug']:false;
  101. $this->_logcallback = isset($options['logcallback'])?$options['logcallback']:false;
  102. }
  103. private function log($log){
  104. if ($this->debug && function_exists($this->_logcallback)) {
  105. if (is_array($log)) $log = print_r($log,true);
  106. return call_user_func($this->_logcallback,$log);
  107. }
  108. }
  109. /**
  110. * 数据XML编码
  111. * @param mixed $data 数据
  112. * @return string
  113. */
  114. public static function data_to_xml($data) {
  115. $xml = '';
  116. foreach ($data as $key => $val) {
  117. is_numeric($key) && $key = "item id=\"$key\"";
  118. $xml .= "<$key>";
  119. $xml .= ( is_array($val) || is_object($val)) ? self::data_to_xml($val) : self::xmlSafeStr($val);
  120. list($key, ) = explode(' ', $key);
  121. $xml .= "</$key>";
  122. }
  123. return $xml;
  124. }
  125. public static function xmlSafeStr($str)
  126. {
  127. return '<![CDATA['.preg_replace("/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/",'',$str).']]>';
  128. }
  129. /**
  130. * XML编码
  131. * @param mixed $data 数据
  132. * @param string $root 根节点名
  133. * @param string $item 数字索引的子节点名
  134. * @param string $attr 根节点属性
  135. * @param string $id 数字索引子节点key转换的属性名
  136. * @param string $encoding 数据编码
  137. * @return string
  138. */
  139. public function xml_encode($data, $root='xml', $item='item', $attr='', $id='id', $encoding='utf-8') {
  140. if(is_array($attr)){
  141. $_attr = array();
  142. foreach ($attr as $key => $value) {
  143. $_attr[] = "{$key}=\"{$value}\"";
  144. }
  145. $attr = implode(' ', $_attr);
  146. }
  147. $attr = trim($attr);
  148. $attr = empty($attr) ? '' : " {$attr}";
  149. $xml = "<{$root}{$attr}>";
  150. $xml .= self::data_to_xml($data, $item, $id);
  151. $xml .= "</{$root}>";
  152. return $xml;
  153. }
  154. /**
  155. * 微信api不支持中文转义的json结构
  156. * @param array $arr
  157. */
  158. static function json_encode($arr) {
  159. $parts = array ();
  160. $is_list = false;
  161. //Find out if the given array is a numerical array
  162. $keys = array_keys ( $arr );
  163. $max_length = count ( $arr ) - 1;
  164. if (($keys [0] === 0) && ($keys [$max_length] === $max_length )) { //See if the first key is 0 and last key is length - 1
  165. $is_list = true;
  166. for($i = 0; $i < count ( $keys ); $i ++) { //See if each key correspondes to its position
  167. if ($i != $keys [$i]) { //A key fails at position check.
  168. $is_list = false; //It is an associative array.
  169. break;
  170. }
  171. }
  172. }
  173. foreach ( $arr as $key => $value ) {
  174. if (is_array ( $value )) { //Custom handling for arrays
  175. if ($is_list)
  176. $parts [] = self::json_encode ( $value ); /* :RECURSION: */
  177. else
  178. $parts [] = '"' . $key . '":' . self::json_encode ( $value ); /* :RECURSION: */
  179. } else {
  180. $str = '';
  181. if (! $is_list)
  182. $str = '"' . $key . '":';
  183. //Custom handling for multiple data types
  184. if (!is_string ( $value ) && is_numeric ( $value ) && $value<2000000000)
  185. $str .= $value; //Numbers
  186. elseif ($value === false)
  187. $str .= 'false'; //The booleans
  188. elseif ($value === true)
  189. $str .= 'true';
  190. else
  191. $str .= '"' . addslashes ( $value ) . '"'; //All other things
  192. // :TODO: Is there any more datatype we should be in the lookout for? (Object?)
  193. $parts [] = $str;
  194. }
  195. }
  196. $json = implode ( ',', $parts );
  197. if ($is_list)
  198. return '[' . $json . ']'; //Return numerical JSON
  199. return '{' . $json . '}'; //Return associative JSON
  200. }
  201. /**
  202. * 过滤文字回复\r\n换行符
  203. * @param string $text
  204. * @return string|mixed
  205. */
  206. private function _auto_text_filter($text) {
  207. if (!$this->_text_filter) return $text;
  208. return str_replace("\r\n", "\n", $text);
  209. }
  210. /**
  211. * GET 请求
  212. * @param string $url
  213. */
  214. private function http_get($url){
  215. $oCurl = curl_init();
  216. if(stripos($url,"https://")!==FALSE){
  217. curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
  218. curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
  219. curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
  220. }
  221. curl_setopt($oCurl, CURLOPT_URL, $url);
  222. curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
  223. $sContent = curl_exec($oCurl);
  224. $aStatus = curl_getinfo($oCurl);
  225. curl_close($oCurl);
  226. if(intval($aStatus["http_code"])==200){
  227. return $sContent;
  228. }else{
  229. return false;
  230. }
  231. }
  232. /**
  233. * POST 请求
  234. * @param string $url
  235. * @param array $param
  236. * @param boolean $post_file 是否文件上传
  237. * @return string content
  238. */
  239. private function http_post($url,$param,$post_file=false){
  240. $oCurl = curl_init();
  241. if(stripos($url,"https://")!==FALSE){
  242. curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
  243. curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
  244. curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
  245. }
  246. if (is_string($param) || $post_file) {
  247. $strPOST = $param;
  248. } else {
  249. $aPOST = array();
  250. foreach($param as $key=>$val){
  251. $aPOST[] = $key."=".urlencode($val);
  252. }
  253. $strPOST = join("&", $aPOST);
  254. }
  255. curl_setopt($oCurl, CURLOPT_URL, $url);
  256. curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
  257. curl_setopt($oCurl, CURLOPT_POST,true);
  258. curl_setopt($oCurl, CURLOPT_POSTFIELDS,$strPOST);
  259. $sContent = curl_exec($oCurl);
  260. $aStatus = curl_getinfo($oCurl);
  261. curl_close($oCurl);
  262. if(intval($aStatus["http_code"])==200){
  263. return $sContent;
  264. }else{
  265. return false;
  266. }
  267. }
  268. /**
  269. * For weixin server validation
  270. */
  271. private function checkSignature($str)
  272. {
  273. $signature = isset($_GET["msg_signature"])?$_GET["msg_signature"]:'';
  274. $timestamp = isset($_GET["timestamp"])?$_GET["timestamp"]:'';
  275. $nonce = isset($_GET["nonce"])?$_GET["nonce"]:'';
  276. $tmpArr = array($str,$this->token, $timestamp, $nonce);//比普通公众平台多了一个加密的密文
  277. sort($tmpArr, SORT_STRING);
  278. $tmpStr = implode($tmpArr);
  279. $shaStr = sha1($tmpStr);
  280. if( $shaStr == $signature ){
  281. return true;
  282. }else{
  283. return false;
  284. }
  285. }
  286. /**
  287. * 微信验证,包括post来的xml解密
  288. * @param bool $return 是否返回
  289. */
  290. public function valid($return=false)
  291. {
  292. $encryptStr="";
  293. if ($_SERVER['REQUEST_METHOD'] == "POST") {
  294. $postStr = file_get_contents("php://input");
  295. $array = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
  296. $this->log($postStr);
  297. if (isset($array['Encrypt'])) {
  298. $encryptStr = $array['Encrypt'];
  299. $this->agentidxml = isset($array['AgentID']) ? $array['AgentID']: '';
  300. }
  301. } else {
  302. $encryptStr = isset($_GET["echostr"]) ? $_GET["echostr"]: '';
  303. }
  304. if ($encryptStr) {
  305. $ret=$this->checkSignature($encryptStr);
  306. }
  307. if (!isset($ret) || !$ret) {
  308. if (!$return) {
  309. die('no access');
  310. } else {
  311. return false;
  312. }
  313. }
  314. $pc = new Prpcrypt($this->encodingAesKey);
  315. $array = $pc->decrypt($encryptStr,$this->appid);
  316. if (!isset($array[0]) || ($array[0] != 0)) {
  317. if (!$return) {
  318. die('解密失败!');
  319. } else {
  320. return false;
  321. }
  322. }
  323. if ($_SERVER['REQUEST_METHOD'] == "POST") {
  324. $this->postxml = $array[1];
  325. //$this->log($array[1]);
  326. return ($this->postxml!="");
  327. } else {
  328. $echoStr = $array[1];
  329. if ($return) {
  330. return $echoStr;
  331. } else {
  332. die($echoStr);
  333. }
  334. }
  335. return false;
  336. }
  337. /**
  338. * 获取微信服务器发来的信息
  339. */
  340. public function getRev()
  341. {
  342. if ($this->_receive) return $this;
  343. $postStr = $this->postxml;
  344. $this->log($postStr);
  345. if (!empty($postStr)) {
  346. $this->_receive = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
  347. if (!isset($this->_receive['AgentID'])) {
  348. $this->_receive['AgentID']=$this->agentidxml; //当前接收消息的应用id
  349. }
  350. }
  351. return $this;
  352. }
  353. /**
  354. * 获取微信服务器发来的信息
  355. */
  356. public function getRevData()
  357. {
  358. return $this->_receive;
  359. }
  360. /**
  361. * 获取微信服务器发来的原始加密信息
  362. */
  363. public function getRevPostXml()
  364. {
  365. return $this->postxml;
  366. }
  367. /**
  368. * 获取消息发送者
  369. */
  370. public function getRevFrom() {
  371. if (isset($this->_receive['FromUserName']))
  372. return $this->_receive['FromUserName'];
  373. else
  374. return false;
  375. }
  376. /**
  377. * 获取消息接受者
  378. */
  379. public function getRevTo() {
  380. if (isset($this->_receive['ToUserName']))
  381. return $this->_receive['ToUserName'];
  382. else
  383. return false;
  384. }
  385. /**
  386. * 获取接收消息的应用id
  387. */
  388. public function getRevAgentID() {
  389. if (isset($this->_receive['AgentID']))
  390. return $this->_receive['AgentID'];
  391. else
  392. return false;
  393. }
  394. /**
  395. * 获取接收消息的类型
  396. */
  397. public function getRevType() {
  398. if (isset($this->_receive['MsgType']))
  399. return $this->_receive['MsgType'];
  400. else
  401. return false;
  402. }
  403. /**
  404. * 获取消息ID
  405. */
  406. public function getRevID() {
  407. if (isset($this->_receive['MsgId']))
  408. return $this->_receive['MsgId'];
  409. else
  410. return false;
  411. }
  412. /**
  413. * 获取消息发送时间
  414. */
  415. public function getRevCtime() {
  416. if (isset($this->_receive['CreateTime']))
  417. return $this->_receive['CreateTime'];
  418. else
  419. return false;
  420. }
  421. /**
  422. * 获取接收消息内容正文
  423. */
  424. public function getRevContent(){
  425. if (isset($this->_receive['Content']))
  426. return $this->_receive['Content'];
  427. else
  428. return false;
  429. }
  430. /**
  431. * 获取接收消息图片
  432. */
  433. public function getRevPic(){
  434. if (isset($this->_receive['PicUrl']))
  435. return array(
  436. 'mediaid'=>$this->_receive['MediaId'],
  437. 'picurl'=>(string)$this->_receive['PicUrl'], //防止picurl为空导致解析出错
  438. );
  439. else
  440. return false;
  441. }
  442. /**
  443. * 获取接收地理位置
  444. */
  445. public function getRevGeo(){
  446. if (isset($this->_receive['Location_X'])){
  447. return array(
  448. 'x'=>$this->_receive['Location_X'],
  449. 'y'=>$this->_receive['Location_Y'],
  450. 'scale'=>(string)$this->_receive['Scale'],
  451. 'label'=>(string)$this->_receive['Label']
  452. );
  453. } else
  454. return false;
  455. }
  456. /**
  457. * 获取上报地理位置事件
  458. */
  459. public function getRevEventGeo(){
  460. if (isset($this->_receive['Latitude'])){
  461. return array(
  462. 'x'=>$this->_receive['Latitude'],
  463. 'y'=>$this->_receive['Longitude'],
  464. 'precision'=>$this->_receive['Precision'],
  465. );
  466. } else
  467. return false;
  468. }
  469. /**
  470. * 获取接收事件推送
  471. */
  472. public function getRevEvent(){
  473. if (isset($this->_receive['Event'])){
  474. $array['event'] = $this->_receive['Event'];
  475. }
  476. if (isset($this->_receive['EventKey']) && !empty($this->_receive['EventKey'])){
  477. $array['key'] = $this->_receive['EventKey'];
  478. }
  479. if (isset($array) && count($array) > 0) {
  480. return $array;
  481. } else {
  482. return false;
  483. }
  484. }
  485. /**
  486. * 获取自定义菜单的扫码推事件信息
  487. *
  488. * 事件类型为以下两种时则调用此方法有效
  489. * Event 事件类型,scancode_push
  490. * Event 事件类型,scancode_waitmsg
  491. *
  492. * @return: array | false
  493. * array (
  494. * 'ScanType'=>'qrcode',
  495. * 'ScanResult'=>'123123'
  496. * )
  497. */
  498. public function getRevScanInfo(){
  499. if (isset($this->_receive['ScanCodeInfo'])){
  500. if (!is_array($this->_receive['SendPicsInfo'])) {
  501. $array=(array)$this->_receive['ScanCodeInfo'];
  502. $this->_receive['ScanCodeInfo']=$array;
  503. }else {
  504. $array=$this->_receive['ScanCodeInfo'];
  505. }
  506. }
  507. if (isset($array) && count($array) > 0) {
  508. return $array;
  509. } else {
  510. return false;
  511. }
  512. }
  513. /**
  514. * 获取自定义菜单的图片发送事件信息
  515. *
  516. * 事件类型为以下三种时则调用此方法有效
  517. * Event 事件类型,pic_sysphoto 弹出系统拍照发图的事件推送
  518. * Event 事件类型,pic_photo_or_album 弹出拍照或者相册发图的事件推送
  519. * Event 事件类型,pic_weixin 弹出微信相册发图器的事件推送
  520. *
  521. * @return: array | false
  522. * array (
  523. * 'Count' => '2',
  524. * 'PicList' =>array (
  525. * 'item' =>array (
  526. * 0 =>array ('PicMd5Sum' => 'aaae42617cf2a14342d96005af53624c'),
  527. * 1 =>array ('PicMd5Sum' => '149bd39e296860a2adc2f1bb81616ff8'),
  528. * ),
  529. * ),
  530. * )
  531. *
  532. */
  533. public function getRevSendPicsInfo(){
  534. if (isset($this->_receive['SendPicsInfo'])){
  535. if (!is_array($this->_receive['SendPicsInfo'])) {
  536. $array=(array)$this->_receive['SendPicsInfo'];
  537. if (isset($array['PicList'])){
  538. $array['PicList']=(array)$array['PicList'];
  539. $item=$array['PicList']['item'];
  540. $array['PicList']['item']=array();
  541. foreach ( $item as $key => $value ){
  542. $array['PicList']['item'][$key]=(array)$value;
  543. }
  544. }
  545. $this->_receive['SendPicsInfo']=$array;
  546. } else {
  547. $array=$this->_receive['SendPicsInfo'];
  548. }
  549. }
  550. if (isset($array) && count($array) > 0) {
  551. return $array;
  552. } else {
  553. return false;
  554. }
  555. }
  556. /**
  557. * 获取自定义菜单的地理位置选择器事件推送
  558. *
  559. * 事件类型为以下时则可以调用此方法有效
  560. * Event 事件类型,location_select 弹出系统拍照发图的事件推送
  561. *
  562. * @return: array | false
  563. * array (
  564. * 'Location_X' => '33.731655000061',
  565. * 'Location_Y' => '113.29955200008047',
  566. * 'Scale' => '16',
  567. * 'Label' => '某某市某某区某某路',
  568. * 'Poiname' => '',
  569. * )
  570. *
  571. */
  572. public function getRevSendGeoInfo(){
  573. if (isset($this->_receive['SendLocationInfo'])){
  574. if (!is_array($this->_receive['SendLocationInfo'])) {
  575. $array=(array)$this->_receive['SendLocationInfo'];
  576. if (empty($array['Poiname'])) {
  577. $array['Poiname']="";
  578. }
  579. if (empty($array['Label'])) {
  580. $array['Label']="";
  581. }
  582. $this->_receive['SendLocationInfo']=$array;
  583. } else {
  584. $array=$this->_receive['SendLocationInfo'];
  585. }
  586. }
  587. if (isset($array) && count($array) > 0) {
  588. return $array;
  589. } else {
  590. return false;
  591. }
  592. }
  593. /**
  594. * 获取接收语音推送
  595. */
  596. public function getRevVoice(){
  597. if (isset($this->_receive['MediaId'])){
  598. return array(
  599. 'mediaid'=>$this->_receive['MediaId'],
  600. 'format'=>$this->_receive['Format'],
  601. );
  602. } else
  603. return false;
  604. }
  605. /**
  606. * 获取接收视频推送
  607. */
  608. public function getRevVideo(){
  609. if (isset($this->_receive['MediaId'])){
  610. return array(
  611. 'mediaid'=>$this->_receive['MediaId'],
  612. 'thumbmediaid'=>$this->_receive['ThumbMediaId']
  613. );
  614. } else
  615. return false;
  616. }
  617. /**
  618. * 设置回复消息
  619. * Example: $obj->text('hello')->reply();
  620. * @param string $text
  621. */
  622. public function text($text='')
  623. {
  624. $msg = array(
  625. 'ToUserName' => $this->getRevFrom(),
  626. 'FromUserName'=>$this->getRevTo(),
  627. 'MsgType'=>self::MSGTYPE_TEXT,
  628. 'Content'=>$this->_auto_text_filter($text),
  629. 'CreateTime'=>time(),
  630. );
  631. $this->Message($msg);
  632. return $this;
  633. }
  634. /**
  635. * 设置回复消息
  636. * Example: $obj->image('media_id')->reply();
  637. * @param string $mediaid
  638. */
  639. public function image($mediaid='')
  640. {
  641. $msg = array(
  642. 'ToUserName' => $this->getRevFrom(),
  643. 'FromUserName'=>$this->getRevTo(),
  644. 'MsgType'=>self::MSGTYPE_IMAGE,
  645. 'Image'=>array('MediaId'=>$mediaid),
  646. 'CreateTime'=>time(),
  647. );
  648. $this->Message($msg);
  649. return $this;
  650. }
  651. /**
  652. * 设置回复消息
  653. * Example: $obj->voice('media_id')->reply();
  654. * @param string $mediaid
  655. */
  656. public function voice($mediaid='')
  657. {
  658. $msg = array(
  659. 'ToUserName' => $this->getRevFrom(),
  660. 'FromUserName'=>$this->getRevTo(),
  661. 'MsgType'=>self::MSGTYPE_IMAGE,
  662. 'Voice'=>array('MediaId'=>$mediaid),
  663. 'CreateTime'=>time(),
  664. );
  665. $this->Message($msg);
  666. return $this;
  667. }
  668. /**
  669. * 设置回复消息
  670. * Example: $obj->video('media_id','title','description')->reply();
  671. * @param string $mediaid
  672. */
  673. public function video($mediaid='',$title='',$description='')
  674. {
  675. $msg = array(
  676. 'ToUserName' => $this->getRevFrom(),
  677. 'FromUserName'=>$this->getRevTo(),
  678. 'MsgType'=>self::MSGTYPE_IMAGE,
  679. 'Video'=>array(
  680. 'MediaId'=>$mediaid,
  681. 'Title'=>$title,
  682. 'Description'=>$description
  683. ),
  684. 'CreateTime'=>time(),
  685. );
  686. $this->Message($msg);
  687. return $this;
  688. }
  689. /**
  690. * 设置回复图文
  691. * @param array $newsData
  692. * 数组结构:
  693. * array(
  694. * "0"=>array(
  695. * 'Title'=>'msg title',
  696. * 'Description'=>'summary text',
  697. * 'PicUrl'=>'http://www.domain.com/1.jpg',
  698. * 'Url'=>'http://www.domain.com/1.html'
  699. * ),
  700. * "1"=>....
  701. * )
  702. */
  703. public function news($newsData=array())
  704. {
  705. $count = count($newsData);
  706. $msg = array(
  707. 'ToUserName' => $this->getRevFrom(),
  708. 'FromUserName'=>$this->getRevTo(),
  709. 'MsgType'=>self::MSGTYPE_NEWS,
  710. 'CreateTime'=>time(),
  711. 'ArticleCount'=>$count,
  712. 'Articles'=>$newsData,
  713. );
  714. $this->Message($msg);
  715. return $this;
  716. }
  717. /**
  718. * 设置发送消息
  719. * @param array $msg 消息数组
  720. * @param bool $append 是否在原消息数组追加
  721. */
  722. public function Message($msg = '',$append = false){
  723. if (is_null($msg)) {
  724. $this->_msg =array();
  725. }elseif (is_array($msg)) {
  726. if ($append)
  727. $this->_msg = array_merge($this->_msg,$msg);
  728. else
  729. $this->_msg = $msg;
  730. return $this->_msg;
  731. } else {
  732. return $this->_msg;
  733. }
  734. }
  735. /**
  736. *
  737. * 回复微信服务器, 此函数支持链式操作
  738. * Example: $this->text('msg tips')->reply();
  739. * @param string $msg 要发送的信息, 默认取$this->_msg
  740. * @param bool $return 是否返回信息而不抛出到浏览器 默认:否
  741. */
  742. public function reply($msg=array(),$return = false)
  743. {
  744. if (empty($msg))
  745. $msg = $this->_msg;
  746. $xmldata= $this->xml_encode($msg);
  747. $this->log($xmldata);
  748. $pc = new Prpcrypt($this->encodingAesKey);
  749. $array = $pc->encrypt($xmldata, $this->appid);
  750. $ret = $array[0];
  751. if ($ret != 0) {
  752. $this->log('encrypt err!');
  753. return false;
  754. }
  755. $timestamp = time();
  756. $nonce = rand(77,999)*rand(605,888)*rand(11,99);
  757. $encrypt = $array[1];
  758. $tmpArr = array($this->token, $timestamp, $nonce,$encrypt);//比普通公众平台多了一个加密的密文
  759. sort($tmpArr, SORT_STRING);
  760. $signature = implode($tmpArr);
  761. $signature = sha1($signature);
  762. $smsg = $this->generate($encrypt, $signature, $timestamp, $nonce);
  763. $this->log($smsg);
  764. if ($return)
  765. return $smsg;
  766. elseif ($smsg){
  767. echo $smsg;
  768. return true;
  769. }else
  770. return false;
  771. }
  772. private function generate($encrypt, $signature, $timestamp, $nonce)
  773. {
  774. //格式化加密信息
  775. $format = "<xml>
  776. <Encrypt><![CDATA[%s]]></Encrypt>
  777. <MsgSignature><![CDATA[%s]]></MsgSignature>
  778. <TimeStamp>%s</TimeStamp>
  779. <Nonce><![CDATA[%s]]></Nonce>
  780. </xml>";
  781. return sprintf($format, $encrypt, $signature, $timestamp, $nonce);
  782. }
  783. /**
  784. * 通用auth验证方法
  785. * @param string $appid
  786. * @param string $appsecret
  787. * @param string $token 手动指定access_token,非必要情况不建议用
  788. */
  789. public function checkAuth($appid='',$appsecret='',$token=''){
  790. if (!$appid || !$appsecret) {
  791. $appid = $this->appid;
  792. $appsecret = $this->appsecret;
  793. }
  794. if ($token) { //手动指定token,优先使用
  795. $this->access_token=$token;
  796. return $this->access_token;
  797. }
  798. //TODO: get the cache access_token
  799. $result = $this->http_get(self::API_URL_PREFIX.self::TOKEN_GET_URL.'corpid='.$appid.'&corpsecret='.$appsecret);
  800. if ($result)
  801. {
  802. $json = json_decode($result,true);
  803. if (!$json || isset($json['errcode'])) {
  804. $this->errCode = $json['errcode'];
  805. $this->errMsg = $json['errmsg'];
  806. return false;
  807. }
  808. $this->access_token = $json['access_token'];
  809. $expire = $json['expires_in'] ? intval($json['expires_in'])-100 : 3600;
  810. //TODO: cache access_token
  811. return $this->access_token;
  812. }
  813. return false;
  814. }
  815. /**
  816. * 删除验证数据
  817. * @param string $appid
  818. */
  819. public function resetAuth($appid=''){
  820. if (!$appid) $appid = $this->appid;
  821. $this->access_token = '';
  822. //TODO: remove cache
  823. return true;
  824. }
  825. /**
  826. * 创建菜单
  827. * @param array $data 菜单数组数据
  828. * example:
  829. * array (
  830. * 'button' => array (
  831. * 0 => array (
  832. * 'name' => '扫码',
  833. * 'sub_button' => array (
  834. * 0 => array (
  835. * 'type' => 'scancode_waitmsg',
  836. * 'name' => '扫码带提示',
  837. * 'key' => 'rselfmenu_0_0',
  838. * ),
  839. * 1 => array (
  840. * 'type' => 'scancode_push',
  841. * 'name' => '扫码推事件',
  842. * 'key' => 'rselfmenu_0_1',
  843. * ),
  844. * ),
  845. * ),
  846. * 1 => array (
  847. * 'name' => '发图',
  848. * 'sub_button' => array (
  849. * 0 => array (
  850. * 'type' => 'pic_sysphoto',
  851. * 'name' => '系统拍照发图',
  852. * 'key' => 'rselfmenu_1_0',
  853. * ),
  854. * 1 => array (
  855. * 'type' => 'pic_photo_or_album',
  856. * 'name' => '拍照或者相册发图',
  857. * 'key' => 'rselfmenu_1_1',
  858. * )
  859. * ),
  860. * ),
  861. * 2 => array (
  862. * 'type' => 'location_select',
  863. * 'name' => '发送位置',
  864. * 'key' => 'rselfmenu_2_0'
  865. * ),
  866. * ),
  867. * )
  868. * type可以选择为以下几种,会收到相应类型的事件推送。请注意,3到8的所有事件,仅支持微信iPhone5.4.1以上版本,
  869. * 和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。
  870. * 1、click:点击推事件
  871. * 2、view:跳转URL
  872. * 3、scancode_push:扫码推事件
  873. * 4、scancode_waitmsg:扫码推事件且弹出“消息接收中”提示框
  874. * 5、pic_sysphoto:弹出系统拍照发图
  875. * 6、pic_photo_or_album:弹出拍照或者相册发图
  876. * 7、pic_weixin:弹出微信相册发图器
  877. * 8、location_select:弹出地理位置选择器
  878. */
  879. public function createMenu($data,$agentid=''){
  880. if ($agentid=='') {
  881. $agentid=$this->agentid;
  882. }
  883. if (!$this->access_token && !$this->checkAuth()) return false;
  884. $result = $this->http_post(self::API_URL_PREFIX.self::MENU_CREATE_URL.'access_token='.$this->access_token.'&agentid='.$agentid,self::json_encode($data));
  885. if ($result)
  886. {
  887. $json = json_decode($result,true);
  888. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  889. $this->errCode = $json['errcode'];
  890. $this->errMsg = $json['errmsg'];
  891. return false;
  892. }
  893. return true;
  894. }
  895. return false;
  896. }
  897. /**
  898. * 获取菜单
  899. * @return array('menu'=>array(....s))
  900. */
  901. public function getMenu($agentid=''){
  902. if ($agentid=='') {
  903. $agentid=$this->agentid;
  904. }
  905. if (!$this->access_token && !$this->checkAuth()) return false;
  906. $result = $this->http_get(self::API_URL_PREFIX.self::MENU_GET_URL.'access_token='.$this->access_token.'&agentid='.$agentid);
  907. if ($result)
  908. {
  909. $json = json_decode($result,true);
  910. if (!$json || isset($json['errcode']) || $json['errcode']!=0) {
  911. $this->errCode = $json['errcode'];
  912. $this->errMsg = $json['errmsg'];
  913. return false;
  914. }
  915. return $json;
  916. }
  917. return false;
  918. }
  919. /**
  920. * 删除菜单
  921. * @return boolean
  922. */
  923. public function deleteMenu($agentid=''){
  924. if ($agentid=='') {
  925. $agentid=$this->agentid;
  926. }
  927. if (!$this->access_token && !$this->checkAuth()) return false;
  928. $result = $this->http_get(self::API_URL_PREFIX.self::MENU_DELETE_URL.'access_token='.$this->access_token.'&agentid='.$agentid);
  929. if ($result)
  930. {
  931. $json = json_decode($result,true);
  932. if (!$json || !empty($json['errcode'])) {
  933. $this->errCode = $json['errcode'];
  934. $this->errMsg = $json['errmsg'];
  935. return false;
  936. }
  937. return true;
  938. }
  939. return false;
  940. }
  941. /**
  942. * 上传多媒体文件 (只有三天的有效期,过期自动被删除)
  943. * 注意:上传大文件时可能需要先调用 set_time_limit(0) 避免超时
  944. * 注意:数组的键值任意,但文件名前必须加@,使用单引号以避免本地路径斜杠被转义
  945. * @param array $data {"media":'@Path\filename.jpg'}
  946. * @param type 媒体文件类型:图片(image)、语音(voice)、视频(video),普通文件(file)
  947. * @return boolean|array
  948. * {
  949. * "type": "image",
  950. * "media_id": "0000001",
  951. * "created_at": "1380000000"
  952. * }
  953. */
  954. public function uploadMedia($data, $type){
  955. if (!$this->access_token && !$this->checkAuth()) return false;
  956. $result = $this->http_post(self::API_URL_PREFIX.self::MEDIA_UPLOAD.'access_token='.$this->access_token.'&type='.$type,$data,true);
  957. if ($result)
  958. {
  959. $json = json_decode($result,true);
  960. if (!$json || !empty($json['errcode'])) {
  961. $this->errCode = $json['errcode'];
  962. $this->errMsg = $json['errmsg'];
  963. return false;
  964. }
  965. return $json;
  966. }
  967. return false;
  968. }
  969. /**
  970. * 根据媒体文件ID获取媒体文件
  971. * @param string $media_id 媒体文件id
  972. * @return raw data
  973. */
  974. public function getMedia($media_id){
  975. if (!$this->access_token && !$this->checkAuth()) return false;
  976. $result = $this->http_get(self::API_URL_PREFIX.self::MEDIA_GET_URL.'access_token='.$this->access_token.'&media_id='.$media_id);
  977. if ($result)
  978. {
  979. $json = json_decode($result,true);
  980. if (isset($json['errcode'])) {
  981. $this->errCode = $json['errcode'];
  982. $this->errMsg = $json['errmsg'];
  983. return false;
  984. }
  985. return $result;
  986. }
  987. return false;
  988. }
  989. /**
  990. * 获取企业微信服务器IP地址列表
  991. * @return array('127.0.0.1','127.0.0.1')
  992. */
  993. public function getServerIp(){
  994. if (!$this->access_token && !$this->checkAuth()) return false;
  995. $result = $this->http_get(self::API_URL_PREFIX.self::CALLBACKSERVER_GET_URL.'access_token='.$this->access_token);
  996. if ($result)
  997. {
  998. $json = json_decode($result,true);
  999. if (!$json || isset($json['errcode'])) {
  1000. $this->errCode = $json['errcode'];
  1001. $this->errMsg = $json['errmsg'];
  1002. return false;
  1003. }
  1004. return $json['ip_list'];
  1005. }
  1006. return false;
  1007. }
  1008. /**
  1009. * 创建部门
  1010. * @param array $data 结构体为:
  1011. * array (
  1012. * "name" => "邮箱产品组", //部门名称
  1013. * "parentid" => "1" //父部门id
  1014. * "order" => "1", //(非必须)在父部门中的次序。从1开始,数字越大排序越靠后
  1015. * )
  1016. * @return boolean|array
  1017. * 成功返回结果
  1018. * {
  1019. * "errcode": 0, //返回码
  1020. * "errmsg": "created", //对返回码的文本描述内容
  1021. * "id": 2 //创建的部门id。
  1022. * }
  1023. */
  1024. public function createDepartment($data){
  1025. if (!$this->access_token && !$this->checkAuth()) return false;
  1026. $result = $this->http_post(self::API_URL_PREFIX.self::DEPARTMENT_CREATE_URL.'access_token='.$this->access_token,self::json_encode($data));
  1027. if ($result)
  1028. {
  1029. $json = json_decode($result,true);
  1030. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1031. $this->errCode = $json['errcode'];
  1032. $this->errMsg = $json['errmsg'];
  1033. return false;
  1034. }
  1035. return $json;
  1036. }
  1037. return false;
  1038. }
  1039. /**
  1040. * 更新部门
  1041. * @param array $data 结构体为:
  1042. * array(
  1043. * "id" => "1" //(必须)部门id
  1044. * "name" => "邮箱产品组", //(非必须)部门名称
  1045. * "parentid" => "1", //(非必须)父亲部门id。根部门id为1
  1046. * "order" => "1", //(非必须)在父部门中的次序。从1开始,数字越大排序越靠后
  1047. * )
  1048. * @return boolean|array 成功返回结果
  1049. * {
  1050. * "errcode": 0, //返回码
  1051. * "errmsg": "updated" //对返回码的文本描述内容
  1052. * }
  1053. */
  1054. public function updateDepartment($data){
  1055. if (!$this->access_token && !$this->checkAuth()) return false;
  1056. $result = $this->http_post(self::API_URL_PREFIX.self::DEPARTMENT_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));
  1057. if ($result)
  1058. {
  1059. $json = json_decode($result,true);
  1060. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1061. $this->errCode = $json['errcode'];
  1062. $this->errMsg = $json['errmsg'];
  1063. return false;
  1064. }
  1065. return $json;
  1066. }
  1067. return false;
  1068. }
  1069. /**
  1070. * 删除部门
  1071. * @param $id
  1072. * @return boolean|array 成功返回结果
  1073. * {
  1074. * "errcode": 0, //返回码
  1075. * "errmsg": "deleted" //对返回码的文本描述内容
  1076. * }
  1077. */
  1078. public function deleteDepartment($id){
  1079. if (!$this->access_token && !$this->checkAuth()) return false;
  1080. $result = $this->http_get(self::API_URL_PREFIX.self::DEPARTMENT_DELETE_URL.'access_token='.$this->access_token.'&id='.$id);
  1081. if ($result)
  1082. {
  1083. $json = json_decode($result,true);
  1084. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1085. $this->errCode = $json['errcode'];
  1086. $this->errMsg = $json['errmsg'];
  1087. return false;
  1088. }
  1089. return $json;
  1090. }
  1091. return false;
  1092. }
  1093. /**
  1094. * 移动部门
  1095. * @param $data
  1096. * array(
  1097. * "department_id" => "5", //所要移动的部门
  1098. * "to_parentid" => "2", //想移动到的父部门节点,根部门为1
  1099. * "to_position" => "1" //(非必须)想移动到的父部门下的位置,1表示最上方,往后位置为2,3,4,以此类推,默认为1
  1100. * )
  1101. * @return boolean|array 成功返回结果
  1102. * {
  1103. * "errcode": 0, //返回码
  1104. * "errmsg": "ok" //对返回码的文本描述内容
  1105. * }
  1106. */
  1107. public function moveDepartment($data){
  1108. if (!$this->access_token && !$this->checkAuth()) return false;
  1109. $result = $this->http_get(self::API_URL_PREFIX.self::DEPARTMENT_MOVE_URL.'access_token='.$this->access_token,self::json_encode($data));
  1110. if ($result)
  1111. {
  1112. $json = json_decode($result,true);
  1113. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1114. $this->errCode = $json['errcode'];
  1115. $this->errMsg = $json['errmsg'];
  1116. return false;
  1117. }
  1118. return $json;
  1119. }
  1120. return false;
  1121. }
  1122. /**
  1123. * 获取部门列表
  1124. * @return boolean|array 成功返回结果
  1125. * {
  1126. * "errcode": 0,
  1127. * "errmsg": "ok",
  1128. * "department": [ //部门列表数据。以部门的order字段从小到大排列
  1129. * {
  1130. * "id": 1,
  1131. * "name": "广州研发中心",
  1132. * "parentid": 0
  1133. * },
  1134. * {
  1135. * "id": 2
  1136. * "name": "邮箱产品部",
  1137. * "parentid": 1
  1138. * }
  1139. * ]
  1140. * }
  1141. */
  1142. public function getDepartment(){
  1143. if (!$this->access_token && !$this->checkAuth()) return false;
  1144. $result = $this->http_get(self::API_URL_PREFIX.self::DEPARTMENT_LIST_URL.'access_token='.$this->access_token);
  1145. if ($result)
  1146. {
  1147. $json = json_decode($result,true);
  1148. if (!$json || !empty($json['errcode'])) {
  1149. $this->errCode = $json['errcode'];
  1150. $this->errMsg = $json['errmsg'];
  1151. return false;
  1152. }
  1153. return $json;
  1154. }
  1155. return false;
  1156. }
  1157. /**
  1158. * 创建成员
  1159. * @param array $data 结构体为:
  1160. * array(
  1161. * "userid" => "zhangsan",
  1162. * "name" => "张三",
  1163. * "department" => [1, 2],
  1164. * "position" => "产品经理",
  1165. * "mobile" => "15913215421",
  1166. * "gender" => 1, //性别。gender=0表示男,=1表示女
  1167. * "tel" => "62394",
  1168. * "email" => "zhangsan@gzdev.com",
  1169. * "weixinid" => "zhangsan4dev"
  1170. * )
  1171. * @return boolean|array
  1172. * 成功返回结果
  1173. * {
  1174. * "errcode": 0, //返回码
  1175. * "errmsg": "created", //对返回码的文本描述内容
  1176. * }
  1177. */
  1178. public function createUser($data){
  1179. if (!$this->access_token && !$this->checkAuth()) return false;
  1180. $result = $this->http_post(self::API_URL_PREFIX.self::USER_CREATE_URL.'access_token='.$this->access_token,self::json_encode($data));
  1181. if ($result)
  1182. {
  1183. $json = json_decode($result,true);
  1184. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1185. $this->errCode = $json['errcode'];
  1186. $this->errMsg = $json['errmsg'];
  1187. return false;
  1188. }
  1189. return $json;
  1190. }
  1191. return false;
  1192. }
  1193. /**
  1194. * 更新成员
  1195. * @param array $data 结构体为:
  1196. * array(
  1197. * "userid" => "zhangsan",
  1198. * "name" => "张三",
  1199. * "department" => [1, 2],
  1200. * "position" => "产品经理",
  1201. * "mobile" => "15913215421",
  1202. * "gender" => 1, //性别。gender=0表示男,=1表示女
  1203. * "tel" => "62394",
  1204. * "email" => "zhangsan@gzdev.com",
  1205. * "weixinid" => "zhangsan4dev"
  1206. * )
  1207. * @return boolean|array 成功返回结果
  1208. * {
  1209. * "errcode": 0, //返回码
  1210. * "errmsg": "updated" //对返回码的文本描述内容
  1211. * }
  1212. */
  1213. public function updateUser($data){
  1214. if (!$this->access_token && !$this->checkAuth()) return false;
  1215. $result = $this->http_post(self::API_URL_PREFIX.self::USER_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));
  1216. if ($result)
  1217. {
  1218. $json = json_decode($result,true);
  1219. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1220. $this->errCode = $json['errcode'];
  1221. $this->errMsg = $json['errmsg'];
  1222. return false;
  1223. }
  1224. return $json;
  1225. }
  1226. return false;
  1227. }
  1228. /**
  1229. * 删除成员
  1230. * @param $userid 员工UserID。对应管理端的帐号
  1231. * @return boolean|array 成功返回结果
  1232. * {
  1233. * "errcode": 0, //返回码
  1234. * "errmsg": "deleted" //对返回码的文本描述内容
  1235. * }
  1236. */
  1237. public function deleteUser($userid){
  1238. if (!$this->access_token && !$this->checkAuth()) return false;
  1239. $result = $this->http_get(self::API_URL_PREFIX.self::USER_DELETE_URL.'access_token='.$this->access_token.'&userid='.$userid);
  1240. if ($result)
  1241. {
  1242. $json = json_decode($result,true);
  1243. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1244. $this->errCode = $json['errcode'];
  1245. $this->errMsg = $json['errmsg'];
  1246. return false;
  1247. }
  1248. return $json;
  1249. }
  1250. return false;
  1251. }
  1252. /**
  1253. * 批量删除成员
  1254. * @param array $userid 员工UserID数组。对应管理端的帐号
  1255. * {
  1256. * 'userid1',
  1257. * 'userid2',
  1258. * 'userid3',
  1259. * }
  1260. * @return boolean|array 成功返回结果
  1261. * {
  1262. * "errcode": 0, //返回码
  1263. * "errmsg": "deleted" //对返回码的文本描述内容
  1264. * }
  1265. */
  1266. public function deleteUsers($userids){
  1267. if (!$userids) return false;
  1268. $data = array('useridlist'=>$userids);
  1269. if (!$this->access_token && !$this->checkAuth()) return false;
  1270. $result = $this->http_get(self::API_URL_PREFIX.self::USER_BATCHDELETE_URL.'access_token='.$this->access_token,self::json_encode($data));
  1271. if ($result)
  1272. {
  1273. $json = json_decode($result,true);
  1274. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1275. $this->errCode = $json['errcode'];
  1276. $this->errMsg = $json['errmsg'];
  1277. return false;
  1278. }
  1279. return $json;
  1280. }
  1281. return false;
  1282. }
  1283. /**
  1284. * 获取成员信息
  1285. * @param $userid 员工UserID。对应管理端的帐号
  1286. * @return boolean|array 成功返回结果
  1287. * {
  1288. * "errcode": 0,
  1289. * "errmsg": "ok",
  1290. * "userid": "zhangsan",
  1291. * "name": "李四",
  1292. * "department": [1, 2],
  1293. * "position": "后台工程师",
  1294. * "mobile": "15913215421",
  1295. * "gender": 1, //性别。gender=0表示男,=1表示女
  1296. * "tel": "62394",
  1297. * "email": "zhangsan@gzdev.com",
  1298. * "weixinid": "lisifordev", //微信号
  1299. * "avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3W..../0", //头像url。注:如果要获取小图将url最后的"/0"改成"/64"即可
  1300. * "status": 1 //关注状态: 1=已关注,2=已冻结,4=未关注
  1301. * "extattr": {"attrs":[{"name":"爱好","value":"旅游"},{"name":"卡号","value":"1234567234"}]}
  1302. * }
  1303. */
  1304. public function getUserInfo($userid){
  1305. if (!$this->access_token && !$this->checkAuth()) return false;
  1306. $result = $this->http_get(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$this->access_token.'&userid='.$userid);
  1307. if ($result)
  1308. {
  1309. $json = json_decode($result,true);
  1310. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1311. $this->errCode = $json['errcode'];
  1312. $this->errMsg = $json['errmsg'];
  1313. return false;
  1314. }
  1315. return $json;
  1316. }
  1317. return false;
  1318. }
  1319. /**
  1320. * 获取部门成员
  1321. * @param $department_id 部门id
  1322. * @param $fetch_child 1/0:是否递归获取子部门下面的成员
  1323. * @param $status 0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
  1324. * @return boolean|array 成功返回结果
  1325. * {
  1326. * "errcode": 0,
  1327. * "errmsg": "ok",
  1328. * "userlist": [
  1329. * {
  1330. * "userid": "zhangsan",
  1331. * "name": "李四"
  1332. * }
  1333. * ]
  1334. * }
  1335. */
  1336. public function getUserList($department_id,$fetch_child=0,$status=0){
  1337. if (!$this->access_token && !$this->checkAuth()) return false;
  1338. $result = $this->http_get(self::API_URL_PREFIX.self::USER_LIST_URL.'access_token='.$this->access_token
  1339. .'&department_id='.$department_id.'&fetch_child='.$fetch_child.'&status='.$status);
  1340. if ($result)
  1341. {
  1342. $json = json_decode($result,true);
  1343. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1344. $this->errCode = $json['errcode'];
  1345. $this->errMsg = $json['errmsg'];
  1346. return false;
  1347. }
  1348. return $json;
  1349. }
  1350. return false;
  1351. }
  1352. /**
  1353. * 获取部门成员详情
  1354. * @param $department_id 部门id
  1355. * @param $fetch_child 1/0:是否递归获取子部门下面的成员
  1356. * @param $status 0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
  1357. * @return boolean|array 成功返回结果
  1358. * {
  1359. * "errcode": 0,
  1360. * "errmsg": "ok",
  1361. * "userlist": [
  1362. * {
  1363. * "userid": "zhangsan",
  1364. * "name": "李四",
  1365. * "department": [1, 2],
  1366. * "position": "后台工程师",
  1367. * "mobile": "15913215421",
  1368. * "gender": 1, //性别。gender=0表示男,=1表示女
  1369. * "tel": "62394",
  1370. * "email": "zhangsan@gzdev.com",
  1371. * "weixinid": "lisifordev", //微信号
  1372. * "avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3W..../0", //头像url。注:如果要获取小图将url最后的"/0"改成"/64"即可
  1373. * "status": 1 //关注状态: 1=已关注,2=已冻结,4=未关注
  1374. * "extattr": {"attrs":[{"name":"爱好","value":"旅游"},{"name":"卡号","value":"1234567234"}]}
  1375. * }
  1376. * ]
  1377. * }
  1378. */
  1379. public function getUserListInfo($department_id,$fetch_child=0,$status=0){
  1380. if (!$this->access_token && !$this->checkAuth()) return false;
  1381. $result = $this->http_get(self::API_URL_PREFIX.self::USER_LIST_INFO_URL.'access_token='.$this->access_token
  1382. .'&department_id='.$department_id.'&fetch_child='.$fetch_child.'&status='.$status);
  1383. if ($result)
  1384. {
  1385. $json = json_decode($result,true);
  1386. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1387. $this->errCode = $json['errcode'];
  1388. $this->errMsg = $json['errmsg'];
  1389. return false;
  1390. }
  1391. return $json;
  1392. }
  1393. return false;
  1394. }
  1395. /**
  1396. * 根据code获取成员信息
  1397. * 通过Oauth2.0或者设置了二次验证时获取的code,用于换取成员的UserId和DeviceId
  1398. *
  1399. * @param $code Oauth2.0或者二次验证时返回的code值
  1400. * @param $agentid 跳转链接时所在的企业应用ID,未填则默认为当前配置的应用id
  1401. * @return boolean|array 成功返回数组
  1402. * array(
  1403. * 'UserId' => 'USERID', //员工UserID
  1404. * 'DeviceId' => 'DEVICEID' //手机设备号(由微信在安装时随机生成)
  1405. * )
  1406. */
  1407. public function getUserId($code,$agentid=0){
  1408. if (!$agentid) $agentid=$this->agentid;
  1409. if (!$this->access_token && !$this->checkAuth()) return false;
  1410. $result = $this->http_get(self::API_URL_PREFIX.self::USER_GETINFO_URL.'access_token='.$this->access_token.'&code='.$code.'&agentid'.$agentid);
  1411. if ($result)
  1412. {
  1413. $json = json_decode($result,true);
  1414. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1415. $this->errCode = $json['errcode'];
  1416. $this->errMsg = $json['errmsg'];
  1417. return false;
  1418. }
  1419. return $json;
  1420. }
  1421. return false;
  1422. }
  1423. /**
  1424. * 邀请成员关注
  1425. * 向未关注企业号的成员发送关注邀请。认证号优先判断顺序weixinid>手机号>邮箱绑定>邮件;非认证号只能邮件邀请
  1426. *
  1427. * @param $userid 用户的userid
  1428. * @param $invite_tips 推送到微信上的提示语(只有认证号可以使用)。当使用微信推送时,该字段默认为“请关注XXX企业号”,邮件邀请时,该字段无效。
  1429. * @return boolean|array 成功返回数组
  1430. * array(
  1431. * 'errcode' => 0,
  1432. * 'errmsg' => 'ok',
  1433. * 'type' => 1 //邀请方式 1.微信邀请 2.邮件邀请
  1434. * )
  1435. */
  1436. public function sendInvite($userid,$invite_tips=''){
  1437. $data = array( 'userid' => $userid );
  1438. if (!$invite_tips) {
  1439. $data['invite_tips'] = $invite_tips
  1440. }
  1441. if (!$this->access_token && !$this->checkAuth()) return false;
  1442. $result = $this->http_post(self::API_URL_PREFIX.self::USER_INVITE_URL.'access_token='.$this->access_token,self::json_encode($data));
  1443. if ($result)
  1444. {
  1445. $json = json_decode($result,true);
  1446. if (!$json || !empty($json['errcode'])) {
  1447. $this->errCode = $json['errcode'];
  1448. $this->errMsg = $json['errmsg'];
  1449. return false;
  1450. }
  1451. return $json;
  1452. }
  1453. return false;
  1454. }
  1455. /**
  1456. * 创建标签
  1457. * @param array $data 结构体为:
  1458. * array(
  1459. * "tagname" => "UI"
  1460. * )
  1461. * @return boolean|array
  1462. * 成功返回结果
  1463. * {
  1464. * "errcode": 0, //返回码
  1465. * "errmsg": "created", //对返回码的文本描述内容
  1466. * "tagid": "1"
  1467. * }
  1468. */
  1469. public function createTag($data){
  1470. if (!$this->access_token && !$this->checkAuth()) return false;
  1471. $result = $this->http_post(self::API_URL_PREFIX.self::TAG_CREATE_URL.'access_token='.$this->access_token,self::json_encode($data));
  1472. if ($result)
  1473. {
  1474. $json = json_decode($result,true);
  1475. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1476. $this->errCode = $json['errcode'];
  1477. $this->errMsg = $json['errmsg'];
  1478. return false;
  1479. }
  1480. return $json;
  1481. }
  1482. return false;
  1483. }
  1484. /**
  1485. * 更新标签
  1486. * @param array $data 结构体为:
  1487. * array(
  1488. * "tagid" => "1",
  1489. * "tagname" => "UI design"
  1490. * )
  1491. * @return boolean|array 成功返回结果
  1492. * {
  1493. * "errcode": 0, //返回码
  1494. * "errmsg": "updated" //对返回码的文本描述内容
  1495. * }
  1496. */
  1497. public function updateTag($data){
  1498. if (!$this->access_token && !$this->checkAuth()) return false;
  1499. $result = $this->http_post(self::API_URL_PREFIX.self::TAG_UPDATE_URL.'access_token='.$this->access_token,self::json_encode($data));
  1500. if ($result)
  1501. {
  1502. $json = json_decode($result,true);
  1503. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1504. $this->errCode = $json['errcode'];
  1505. $this->errMsg = $json['errmsg'];
  1506. return false;
  1507. }
  1508. return $json;
  1509. }
  1510. return false;
  1511. }
  1512. /**
  1513. * 删除标签
  1514. * @param $tagid 标签TagID
  1515. * @return boolean|array 成功返回结果
  1516. * {
  1517. * "errcode": 0, //返回码
  1518. * "errmsg": "deleted" //对返回码的文本描述内容
  1519. * }
  1520. */
  1521. public function deleteTag($tagid){
  1522. if (!$this->access_token && !$this->checkAuth()) return false;
  1523. $result = $this->http_get(self::API_URL_PREFIX.self::TAG_DELETE_URL.'access_token='.$this->access_token.'&tagid='.$tagid);
  1524. if ($result)
  1525. {
  1526. $json = json_decode($result,true);
  1527. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1528. $this->errCode = $json['errcode'];
  1529. $this->errMsg = $json['errmsg'];
  1530. return false;
  1531. }
  1532. return $json;
  1533. }
  1534. return false;
  1535. }
  1536. /**
  1537. * 获取标签成员
  1538. * @param $tagid 标签TagID
  1539. * @return boolean|array 成功返回结果
  1540. * {
  1541. * "errcode": 0,
  1542. * "errmsg": "ok",
  1543. * "userlist": [
  1544. * {
  1545. * "userid": "zhangsan",
  1546. * "name": "李四"
  1547. * }
  1548. * ]
  1549. * }
  1550. */
  1551. public function getTag($tagid){
  1552. if (!$this->access_token && !$this->checkAuth()) return false;
  1553. $result = $this->http_get(self::API_URL_PREFIX.self::TAG_GET_URL.'access_token='.$this->access_token.'&tagid='.$tagid);
  1554. if ($result)
  1555. {
  1556. $json = json_decode($result,true);
  1557. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1558. $this->errCode = $json['errcode'];
  1559. $this->errMsg = $json['errmsg'];
  1560. return false;
  1561. }
  1562. return $json;
  1563. }
  1564. return false;
  1565. }
  1566. /**
  1567. * 增加标签成员
  1568. * @param array $data 结构体为:
  1569. * array (
  1570. * "tagid" => "1",
  1571. * "userlist" => array( //企业员工ID列表
  1572. * "user1",
  1573. * "user2"
  1574. * )
  1575. * )
  1576. * @return boolean|array
  1577. * 成功返回结果
  1578. * {
  1579. * "errcode": 0, //返回码
  1580. * "errmsg": "ok", //对返回码的文本描述内容
  1581. * "invalidlist":"usr1|usr2|usr" //若部分userid非法,则会有此段。不在权限内的员工ID列表,以“|”分隔
  1582. * }
  1583. */
  1584. public function addTagUser($data){
  1585. if (!$this->access_token && !$this->checkAuth()) return false;
  1586. $result = $this->http_post(self::API_URL_PREFIX.self::TAG_ADDUSER_URL.'access_token='.$this->access_token,self::json_encode($data));
  1587. if ($result)
  1588. {
  1589. $json = json_decode($result,true);
  1590. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1591. $this->errCode = $json['errcode'];
  1592. $this->errMsg = $json['errmsg'];
  1593. return false;
  1594. }
  1595. return $json;
  1596. }
  1597. return false;
  1598. }
  1599. /**
  1600. * 删除标签成员
  1601. * @param array $data 结构体为:
  1602. * array (
  1603. * "tagid" => "1",
  1604. * "userlist" => array( //企业员工ID列表
  1605. * "user1",
  1606. * "user2"
  1607. * )
  1608. * )
  1609. * @return boolean|array
  1610. * 成功返回结果
  1611. * {
  1612. * "errcode": 0, //返回码
  1613. * "errmsg": "deleted", //对返回码的文本描述内容
  1614. * "invalidlist":"usr1|usr2|usr" //若部分userid非法,则会有此段。不在权限内的员工ID列表,以“|”分隔
  1615. * }
  1616. */
  1617. public function delTagUser($data){
  1618. if (!$this->access_token && !$this->checkAuth()) return false;
  1619. $result = $this->http_post(self::API_URL_PREFIX.self::TAG_DELUSER_URL.'access_token='.$this->access_token,self::json_encode($data));
  1620. if ($result)
  1621. {
  1622. $json = json_decode($result,true);
  1623. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1624. $this->errCode = $json['errcode'];
  1625. $this->errMsg = $json['errmsg'];
  1626. return false;
  1627. }
  1628. return $json;
  1629. }
  1630. return false;
  1631. }
  1632. /**
  1633. * 获取标签列表
  1634. * @return boolean|array 成功返回数组结果,这里附上json样例
  1635. * {
  1636. * "errcode": 0,
  1637. * "errmsg": "ok",
  1638. * "taglist":[
  1639. * {"tagid":1,"tagname":"a"},
  1640. * {"tagid":2,"tagname":"b"}
  1641. * ]
  1642. * }
  1643. */
  1644. public function getTagList(){
  1645. if (!$this->access_token && !$this->checkAuth()) return false;
  1646. $result = $this->http_get(self::API_URL_PREFIX.self::TAG_LIST_URL.'access_token='.$this->access_token);
  1647. if ($result)
  1648. {
  1649. $json = json_decode($result,true);
  1650. if (!$json || !empty($json['errcode'])) {
  1651. $this->errCode = $json['errcode'];
  1652. $this->errMsg = $json['errmsg'];
  1653. return false;
  1654. }
  1655. return $json;
  1656. }
  1657. return false;
  1658. }
  1659. /**
  1660. * 主动发送信息接口
  1661. * @param array $data 结构体为:
  1662. * array(
  1663. * "touser" => "UserID1|UserID2|UserID3",
  1664. * "toparty" => "PartyID1|PartyID2 ",
  1665. * "totag" => "TagID1|TagID2 ",
  1666. * "safe":"0" //是否为保密消息,对于news无效
  1667. * "agentid" => "001", //应用id
  1668. * "msgtype" => "text", //根据信息类型,选择下面对应的信息结构体
  1669. *
  1670. * "text" => array(
  1671. * "content" => "Holiday Request For Pony(http://xxxxx)"
  1672. * ),
  1673. *
  1674. * "image" => array(
  1675. * "media_id" => "MEDIA_ID"
  1676. * ),
  1677. *
  1678. * "voice" => array(
  1679. * "media_id" => "MEDIA_ID"
  1680. * ),
  1681. *
  1682. * " video" => array(
  1683. * "media_id" => "MEDIA_ID",
  1684. * "title" => "Title",
  1685. * "description" => "Description"
  1686. * ),
  1687. *
  1688. * "file" => array(
  1689. * "media_id" => "MEDIA_ID"
  1690. * ),
  1691. *
  1692. * "news" => array( //不支持保密
  1693. * "articles" => array( //articles 图文消息,一个图文消息支持1到10个图文
  1694. * array(
  1695. * "title" => "Title", //标题
  1696. * "description" => "Description", //描述
  1697. * "url" => "URL", //点击后跳转的链接。可根据url里面带的code参数校验员工的真实身份。
  1698. * "picurl" => "PIC_URL", //图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640*320,
  1699. * //小图80*80。如不填,在客户端不显示图片
  1700. * ),
  1701. * )
  1702. * ),
  1703. *
  1704. * "mpnews" => array(
  1705. * "articles" => array( //articles 图文消息,一个图文消息支持1到10个图文
  1706. * array(
  1707. * "title" => "Title", //图文消息的标题
  1708. * "thumb_media_id" => "id", //图文消息缩略图的media_id
  1709. * "author" => "Author", //图文消息的作者(可空)
  1710. * "content_source_url" => "URL", //图文消息点击“阅读原文”之后的页面链接(可空)
  1711. * "content" => "Content" //图文消息的内容,支持html标签
  1712. * "digest" => "Digest description", //图文消息的描述
  1713. * "show_cover_pic" => "0" //是否显示封面,1为显示,0为不显示(可空)
  1714. * ),
  1715. * )
  1716. * )
  1717. * )
  1718. * 请查看官方开发文档中的 发送消息 -> 消息类型及数据格式
  1719. *
  1720. * @return boolean|array
  1721. * 如果对应用或收件人、部门、标签任何一个无权限,则本次发送失败;
  1722. * 如果收件人、部门或标签不存在,发送仍然执行,但返回无效的部分。
  1723. * {
  1724. * "errcode": 0,
  1725. * "errmsg": "ok",
  1726. * "invaliduser": "UserID1",
  1727. * "invalidparty":"PartyID1",
  1728. * "invalidtag":"TagID1"
  1729. * }
  1730. */
  1731. public function sendMessage($data){
  1732. if (!$this->access_token && !$this->checkAuth()) return false;
  1733. $result = $this->http_post(self::API_URL_PREFIX.self::MASS_SEND_URL.'access_token='.$this->access_token,self::json_encode($data));
  1734. if ($result)
  1735. {
  1736. $json = json_decode($result,true);
  1737. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1738. $this->errCode = $json['errcode'];
  1739. $this->errMsg = $json['errmsg'];
  1740. return false;
  1741. }
  1742. return $json;
  1743. }
  1744. return false;
  1745. }
  1746. /**
  1747. * 二次验证
  1748. * 企业在开启二次验证时,必须填写企业二次验证页面的url。
  1749. * 当员工绑定通讯录中的帐号后,会收到一条图文消息,
  1750. * 引导员工到企业的验证页面验证身份,企业在员工验证成功后,
  1751. * 调用如下接口即可让员工关注成功。
  1752. *
  1753. * @param $userid
  1754. * @return boolean|array 成功返回结果
  1755. * {
  1756. * "errcode": 0, //返回码
  1757. * "errmsg": "ok" //对返回码的文本描述内容
  1758. * }
  1759. */
  1760. public function authSucc($userid){
  1761. if (!$this->access_token && !$this->checkAuth()) return false;
  1762. $result = $this->http_get(self::API_URL_PREFIX.self::AUTHSUCC_URL.'access_token='.$this->access_token.'&userid='.$userid);
  1763. if ($result)
  1764. {
  1765. $json = json_decode($result,true);
  1766. if (!$json || !empty($json['errcode']) || $json['errcode']!=0) {
  1767. $this->errCode = $json['errcode'];
  1768. $this->errMsg = $json['errmsg'];
  1769. return false;
  1770. }
  1771. return $json;
  1772. }
  1773. return false;
  1774. }
  1775. /**
  1776. * oauth 授权跳转接口
  1777. * @param string $callback 回调URI
  1778. * @param string $state 重定向后会带上state参数,企业可以填写a-zA-Z0-9的参数值
  1779. * @return string
  1780. */
  1781. public function getOauthRedirect($callback,$state='STATE',$scope='snsapi_base'){
  1782. return self::OAUTH_PREFIX.self::OAUTH_AUTHORIZE_URL.'appid='.$this->appid.'&redirect_uri='.urlencode($callback).'&response_type=code&scope='.$scope.'&state='.$state.'#wechat_redirect';
  1783. }
  1784. }
  1785. /**
  1786. * PKCS7Encoder class
  1787. *
  1788. * 提供基于PKCS7算法的加解密接口.
  1789. */
  1790. class PKCS7Encoder
  1791. {
  1792. public static $block_size = 32;
  1793. /**
  1794. * 对需要加密的明文进行填充补位
  1795. * @param $text 需要进行填充补位操作的明文
  1796. * @return 补齐明文字符串
  1797. */
  1798. function encode($text)
  1799. {
  1800. $block_size = PKCS7Encoder::$block_size;
  1801. $text_length = strlen($text);
  1802. //计算需要填充的位数
  1803. $amount_to_pad = PKCS7Encoder::$block_size - ($text_length % PKCS7Encoder::$block_size);
  1804. if ($amount_to_pad == 0) {
  1805. $amount_to_pad = PKCS7Encoder::block_size;
  1806. }
  1807. //获得补位所用的字符
  1808. $pad_chr = chr($amount_to_pad);
  1809. $tmp = "";
  1810. for ($index = 0; $index < $amount_to_pad; $index++) {
  1811. $tmp .= $pad_chr;
  1812. }
  1813. return $text . $tmp;
  1814. }
  1815. /**
  1816. * 对解密后的明文进行补位删除
  1817. * @param decrypted 解密后的明文
  1818. * @return 删除填充补位后的明文
  1819. */
  1820. function decode($text)
  1821. {
  1822. $pad = ord(substr($text, -1));
  1823. if ($pad < 1 || $pad > PKCS7Encoder::$block_size) {
  1824. $pad = 0;
  1825. }
  1826. return substr($text, 0, (strlen($text) - $pad));
  1827. }
  1828. }
  1829. /**
  1830. * Prpcrypt class
  1831. *
  1832. * 提供接收和推送给公众平台消息的加解密接口.
  1833. */
  1834. class Prpcrypt
  1835. {
  1836. public $key;
  1837. function Prpcrypt($k)
  1838. {
  1839. $this->key = base64_decode($k . "=");
  1840. }
  1841. /**
  1842. * 对明文进行加密
  1843. * @param string $text 需要加密的明文
  1844. * @return string 加密后的密文
  1845. */
  1846. public function encrypt($text, $appid)
  1847. {
  1848. try {
  1849. //获得16位随机字符串,填充到明文之前
  1850. $random = $this->getRandomStr();//"aaaabbbbccccdddd";
  1851. $text = $random . pack("N", strlen($text)) . $text . $appid;
  1852. // 网络字节序
  1853. $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
  1854. $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
  1855. $iv = substr($this->key, 0, 16);
  1856. //使用自定义的填充方式对明文进行补位填充
  1857. $pkc_encoder = new PKCS7Encoder;
  1858. $text = $pkc_encoder->encode($text);
  1859. mcrypt_generic_init($module, $this->key, $iv);
  1860. //加密
  1861. $encrypted = mcrypt_generic($module, $text);
  1862. mcrypt_generic_deinit($module);
  1863. mcrypt_module_close($module);
  1864. // print(base64_encode($encrypted));
  1865. //使用BASE64对加密后的字符串进行编码
  1866. return array(ErrorCode::$OK, base64_encode($encrypted));
  1867. } catch (Exception $e) {
  1868. //print $e;
  1869. return array(ErrorCode::$EncryptAESError, null);
  1870. }
  1871. }
  1872. /**
  1873. * 对密文进行解密
  1874. * @param string $encrypted 需要解密的密文
  1875. * @return string 解密得到的明文
  1876. */
  1877. public function decrypt($encrypted, $appid)
  1878. {
  1879. try {
  1880. //使用BASE64对需要解密的字符串进行解码
  1881. $ciphertext_dec = base64_decode($encrypted);
  1882. $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
  1883. $iv = substr($this->key, 0, 16);
  1884. mcrypt_generic_init($module, $this->key, $iv);
  1885. //解密
  1886. $decrypted = mdecrypt_generic($module, $ciphertext_dec);
  1887. mcrypt_generic_deinit($module);
  1888. mcrypt_module_close($module);
  1889. } catch (Exception $e) {
  1890. return array(ErrorCode::$DecryptAESError, null);
  1891. }
  1892. try {
  1893. //去除补位字符
  1894. $pkc_encoder = new PKCS7Encoder;
  1895. $result = $pkc_encoder->decode($decrypted);
  1896. //去除16位随机字符串,网络字节序和AppId
  1897. if (strlen($result) < 16)
  1898. return "";
  1899. $content = substr($result, 16, strlen($result));
  1900. $len_list = unpack("N", substr($content, 0, 4));
  1901. $xml_len = $len_list[1];
  1902. $xml_content = substr($content, 4, $xml_len);
  1903. $from_appid = substr($content, $xml_len + 4);
  1904. } catch (Exception $e) {
  1905. //print $e;
  1906. return array(ErrorCode::$IllegalBuffer, null);
  1907. }
  1908. if ($from_appid != $appid)
  1909. return array(ErrorCode::$ValidateAppidError, null);
  1910. return array(0, $xml_content);
  1911. }
  1912. /**
  1913. * 随机生成16位字符串
  1914. * @return string 生成的字符串
  1915. */
  1916. function getRandomStr()
  1917. {
  1918. $str = "";
  1919. $str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
  1920. $max = strlen($str_pol) - 1;
  1921. for ($i = 0; $i < 16; $i++) {
  1922. $str .= $str_pol[mt_rand(0, $max)];
  1923. }
  1924. return $str;
  1925. }
  1926. }
  1927. /**
  1928. * error code
  1929. * 仅用作类内部使用,不用于官方API接口的errCode码
  1930. */
  1931. class ErrorCode
  1932. {
  1933. public static $OK = 0;
  1934. public static $ValidateSignatureError = 40001;
  1935. public static $ParseXmlError = 40002;
  1936. public static $ComputeSignatureError = 40003;
  1937. public static $IllegalAesKey = 40004;
  1938. public static $ValidateAppidError = 40005;
  1939. public static $EncryptAESError = 40006;
  1940. public static $DecryptAESError = 40007;
  1941. public static $IllegalBuffer = 40008;
  1942. public static $EncodeBase64Error = 40009;
  1943. public static $DecodeBase64Error = 40010;
  1944. public static $GenReturnXmlError = 40011;
  1945. public static $errCode=array(
  1946. '0'=>'无问题',
  1947. '40001'=>'签名验证错误',
  1948. '40002'=>'xml解析失败',
  1949. '40003'=>'sha加密生成签名失败',
  1950. '40004'=>'encodingAesKey 非法',
  1951. '40005'=>'appid 校验错误',
  1952. '40006'=>'aes 加密失败',
  1953. '40007'=>'aes 解密失败',
  1954. '40008'=>'解密后得到的buffer非法',
  1955. '40009'=>'base64加密失败',
  1956. '40010'=>'base64解密失败',
  1957. '40011'=>'生成xml失败',
  1958. );
  1959. public static function getErrText($err) {
  1960. if (isset(self::$errCode[$err])) {
  1961. return self::$errCode[$err];
  1962. }else {
  1963. return false;
  1964. };
  1965. }
  1966. }