config = Dever::config('wechat', $type)->cAll; $type = $this->config['type']; if (!$project) { $appid = Dever::input('appid'); if ($appid) { $project = Dever::db('token/project')->one(array('option_type' => $type, 'option_appid' => $appid)); } /* if (!$project) { $project = Dever::db('token/project')->one(array('option_type' => $type)); } */ if (!$project) { $project = Dever::input('project', 1); } } if (is_numeric($project)) { $project = Dever::db('token/project')->one(array('option_type' => $type, 'option_id' => $project)); } if (!$project) { Dever::alert('project is not exits!'); } $this->project = $project; } /** * 获取当前站点的配置 * * @return mixed */ public function project() { return $this->project; } /** * 获取当前基本的配置 * * @return mixed */ public function config() { return $this->config; } /** * 更新数据库 * state true为强制更新数据库中的token数据 * * @return mixed */ private function save($type = 'ticket', $value, $expires = false, $interval = 4000, $data = false, $state = false) { $refresh = false; if (strpos($type, '.')) { $temp = explode('.', $type); if ($temp[1] == 'refresh') { $refresh = true; $temp[1] = 'oauth'; } $table = 'token/' . $temp[1]; } else { $table = 'token/' . $type; } $db = Dever::db($table); if ($data) { if (isset($data['id'])) { $where['option_id'] = $data['id']; unset($data['id']); } if (isset($data['openid'])) { $where['option_openid'] = $data['openid']; } if (isset($data['unionid'])) { $where['option_unionid'] = $data['unionid']; } } $where['option_project_id'] = $this->project['id']; $info = $db->one($where); $update = false; if ($state == true) { $update = true; } elseif ($type == 'token' && isset($this->project['url']) && $this->project['url']) { $update = true; } elseif ($info && time() - $info['mdate'] >= $info['expires']) { $update = true; } elseif($info) { return $info; } if (!$info) { $update = false; } if (!$value) { $value = $this->param($type, $info); } if (is_array($value) || (is_string($value) && strstr($value, 'http://'))) { # 为方便测试,这里可以直接用接口返回的token $result = array(); if ($type == 'token' && isset($this->project['url']) && $this->project['url']) { $param = array('type' => $type, 'appid' => $this->project['appid']); $param = Dever::token($param, $this->project['secret']); $result = Dever::curl($this->project['url'], $param); $result = Dever::json_decode($result); if (isset($result['data'])) { $result = $result['data']; } } if (!$result) { if ($refresh) { $result = $this->curl(false, $value, false, $type); } else { $result = $this->curl(false, $value, true, $type); } } $key = $type; if ($result && isset($result[$key])) { $data = $result; $data['value'] = $result[$key]; $data['expires'] = $result['expires_in']; } } else { $data['value'] = $value; $data['expires'] = $expires; } if ($data && isset($data['value']) && $data['value']) { $data['project_id'] = $this->project['id']; $expires = $data['expires'] - $interval; if ($expires <= 0) { $data['expires'] = $data['expires'] - 300; } else { $data['expires'] = $expires; } if ($update == true) { $data['where_id'] = $info['id']; $id = $info['id']; $db->update($data); } else { $id = $db->insert($data); } $data['id'] = $id; if ($id > 0 && isset($result['callback'])) { foreach ($result['callback'] as $v) { Dever::load($v[0], $id, $v[1], $this->project['id']); } } } elseif($info && $info['value']) { $data = $info; $data['value'] = $info['value']; } return $data; } /** * 获取最新的token * * @return mixed */ public function token($value = false, $expires = false, $interval = 4000, $state = false) { $result = $this->save('token', $value, $expires, $interval, false, $state); return $result['value']; } /** * 获取最新的ticket * * @return mixed */ public function ticket($value = false, $expires = false, $interval = 200, $state = false) { $result = $this->save('ticket', $value, $expires, $interval, false, $state); return $result['value']; } /** * 获取最新的oauth token * * @return mixed */ public function oauth($param, $interval = 4000, $state = false) { if (is_array($param) && isset($param['auth_code'])) { $result = $this->curl('oauth.oauth', $param); if (isset($result['oauth.oauth'])) { return $this->save('oauth.oauth', $result['oauth.oauth'], $result['expires_in'], $interval, $result); } else { Dever::alert('oauth error'); } } else { if (is_numeric($param)) { $id = $param; $param = array(); $param['id'] = $id; } return $this->save('oauth.refresh', false, false, $interval, $param, $state); } } /** * 获取最新的code * * @return mixed */ public function code($value = false, $expires = false, $interval = 200) { $result = $this->save('oauth.code', $value, $expires, $interval, false, true); return $result['value']; } /** * 获取最新的openid * * @return mixed */ public function openid($id, $key = 'openid') { $info = Dever::db('token/oauth')->one($id); return $info[$key]; } /** * 获取最新的oauth login地址 * * @return mixed */ public function login($callback = false, $code = false, $location = true) { if (!$code) { $code = $this->code(); } $callback = Dever::url($callback); $config = $this->param('oauth.login', array('code' => $code, 'redirect' => $callback)); $url = $config['url'] . http_build_query($config['param']); if ($location == true) { Dever::location($url); } return $url; } /** * 从wechat获取数据 * * @return mixed */ public function curl($method, $param = array(), $alert = true, $type = false) { if (!$this->alert) { if (!$alert) { $this->alert = 1; } else { $this->alert = 2; } } //return array(); if (is_string($param)) { $result = json_decode(Dever::curl($param), true); } else { if ($method) { $param = $this->param($method, $param); } if ($param['json']) { $param['param'] = json_encode($param['param'], JSON_UNESCAPED_UNICODE); } $result = Dever::curl($param['url'], $param['param'], $param['method'], $param['json']); if (isset($param['response']['img'])) { return $result; } $result = json_decode($result, true); $this->log($result, $param['name'], $param['url'], $param['param']); } if (isset($result['errcode']) && $result['errcode'] != 0) { if ($result['errcode'] == 40001 || $result['errcode'] == 41001) { $token = $this->token(false, false, 4000, true); return $this->curl($method, $param, $alert, $type); } $result = $param + $result; Dever::log($result); if ($alert && $this->alert == 2) { Dever::alert(json_encode($result, JSON_UNESCAPED_UNICODE)); } } if (isset($param['response'])) { foreach ($param['response'] as $k => $v) { if (strpos($k, '.')) { $temp = explode('.', $k); if (isset($result[$temp[0]][$temp[1]])) { $result[$v] = $result[$temp[0]][$temp[1]]; } } elseif (isset($result[$k])) { $result[$v] = $result[$k]; } if (strpos($v, 'callback.') !== false) { $temp = explode('callback.', $v); $result['callback'][] = array($temp[1], $result[$v]); } } } return $result; } public function log($result, $name, $url, $param) { $insert['name'] = $name; $insert['url'] = $url; $insert['result'] = json_encode($result, JSON_UNESCAPED_UNICODE); $insert['param'] = json_encode($param, JSON_UNESCAPED_UNICODE); Dever::db('token/log')->insert($insert); } /** * 拼装wechat需要的参数 * * @return mixed */ public function param($method, $param = array()) { if (strpos($method, '.')) { $temp = explode('.', $method); $config = $this->config[$temp[0]][$temp[1]]; } else { if (!isset($this->config[$method])) { return false; } $config = $this->config[$method]; } if (!$param) { $param = array(); } $param = $this->project + $param; //print_r($param);die; foreach ($config['param'] as $k => $v) { if ($v == 'token') { $config['url'] .= $k . '=' . $this->token(); unset($config['param'][$k]); } elseif ($v == 'ticket') { $config['param'][$k] = $this->ticket(); } elseif ($v == 'code') { $config['param'][$k] = $this->code(); } elseif ($v == 'oauth') { if (!isset($param['oauth'])) { Dever::alert('oauth erorr'); } elseif (is_numeric($param['oauth'])) { $oauth = $this->oauth($param['oauth']); $param['oauth'] = $oauth['value']; } $config['url'] .= $k . '=' . $param['oauth']; unset($config['param'][$k]); } elseif (!is_array($v) && isset($param[$v])) { $config['param'][$k] = $param[$v]; } elseif($v) { $config['param'][$k] = $this->replace($v, $param); } } if (isset($config['param']['shipping_list']) && $config['param']['shipping_list'] == 'shipping_list') { unset($config['param']['shipping_list']); } $config['json'] = isset($config['json']) && $config['json'] ? true : false; return $config; } /** * 替换{} * * @return mixed */ public function replace($value, $param) { if (isset($param['domain']) && is_string($value) && strpos($value, '{domain}') !== false) { foreach ($param['domain'] as $k => $v) { $param['domain'][$k] = str_replace('{domain}', $v, $value); } return $param['domain']; } if (is_array($value)) { foreach ($value as $k => $v) { if (isset($param[$v])) { $value[$k] = $param[$v]; } else { $value[$k] = $this->replace($v, $param); } } $value = json_encode($value, JSON_UNESCAPED_UNICODE); } return $value; } /** * 消息解密 * * @return mixed */ public function decode($sign, $timestamp, $nonce, $encrypt) { include(DEVER_PROJECT_PATH . 'example/wxBizMsgCrypt.php'); $crypt = new \WXBizMsgCrypt($this->project['token'], $this->project['key'], $this->project['appid']); $format = ""; $xml = sprintf($format, $encrypt); $result = ''; $code = $crypt->decryptMsg($sign, $timestamp, $nonce, $xml, $result); if ($code == 0) { libxml_disable_entity_loader(true); $result = (array) simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA); } return $result; } /** * 获取nonce * * @return mixed */ public function nonce() { return substr(md5(microtime()), rand(10, 15)); } /** * 获取signature * * @return mixed */ public function signature($ticket, $url, $timestamp, $noncestr) { /* $info = array(); $info['jsapi_ticket'] = $ticket; $info['url'] = $url; $info['timestamp'] = $timestamp; $info['noncestr'] = $noncestr; ksort($info); */ $signature_string = "jsapi_ticket=$ticket&noncestr=$noncestr×tamp=$timestamp&url=$url"; //$signature_string = substr(http_build_query($info), 0, -1); return sha1($signature_string); } /** * 获取sign签名数据包 * * @return mixed */ public function sign($url) { $ticket = $this->ticket(); if (!$url) { $url = Dever::url(); } else { $url = urldecode($url); } $timestamp = time(); $noncestr = $this->nonce(); $signature = $this->signature($ticket, $url, $timestamp, $noncestr); $sign = array(); $sign['appId'] = $this->project['appid']; $sign['nonceStr'] = $noncestr; $sign['timestamp'] = $timestamp; $sign['url'] = $url; $sign['signature'] = $signature; return $sign; } }