'无效的自定义配置', 85014 => '无效的模版编号', 85043 => '模版错误', 85044 => '代码包超过大小限制', 85045 => 'ext_json有不存在的路径', 85046 => 'tabBar中缺少 path', 85047 => 'pages字段为空', 85048 => 'ext_json解析失败', 80082 => '没有权限使用该插件', 80067 => '找不到使用的插件', 80066 => '非法的插件版本', 86000 => '不是由第三方代小程序进行调用', 86001 => '不存在第三方的已经提交的代码', 85006 => '标签格式错误', 85007 => '页面路径错误', 85008 => '类目填写错误', 85009 => '已经有正在审核的版本', 85077 => '小程序类目信息失效(类目中含有官方下架的类目,请重新选择类目)', 86002 => '小程序还未设置昵称、头像、简介。请先设置完后再重新提交', 85085 => '小程序提审数量已达本月上限,请点击查看《临时quota申请流程》', 85086 => '提交代码审核之前需提前上传代码', 85087 => '小程序已使用 api navigateToMiniProgram,请声明跳转 appid 列表后再次提交', 87006 => '小游戏不能提交', 86007 => '小程序禁止提交', 87013 => '撤回次数达到上限(每天一次,每个月 10 次)', 85019 => '没有审核版本', 85020 => '审核状态未满足发布' ]; public $officialAccount; public $miniProgram; public function __construct($site_id = 0) { // 三方平台配置 $this->site_id = $site_id; $config_model = new Config(); $config_result = $config_model->getOplatformConfig(); $config = $config_result["data"]; if (!empty($config)) { $config_info = $config["value"]; $this->openConfig = $config_info; } $config = [ 'app_id' => $config_info["appid"] ?? '', 'secret' => $config_info["secret"] ?? '', 'token' => $config_info["token"] ?? '', 'aes_key' => $config_info["aes_key"] ?? '', 'log' => [ 'level' => 'debug', 'permission' => 0777, 'file' => 'runtime/log/wechat/easywechat.logs', ], ]; $this->app = Factory::openPlatform($config); $this->app->rebind('request', request()); $this->app->rebind('cache', Cache::store('redis_public')); $this->SetVerifyTicket(); $this->initWechatPlatformAccount($config); // 获取授权小程序配置 $weapp_config_model = new WeappConfig(); $weapp_config = $weapp_config_model->getWeappConfig($site_id); $weapp_config = $weapp_config['data']['value']; $this->appid = $weapp_config['authorizer_appid'] ?? ''; $this->refreshToken = $weapp_config['authorizer_refresh_token'] ?? ''; } public function app($type = 'wechat') { if ($type == "wechat") { // 代公众号实现业务 $officialAccount = $this->app->officialAccount($this->appid, $this->refreshToken ?? null); $this->officialAccount = $officialAccount; $account = $officialAccount; } else { // 代小程序实现业务 $miniProgram = $this->app->miniProgram($this->appid, $this->refreshToken ?? null); $this->miniProgram = $miniProgram; $account = $miniProgram; } return $account; } public function openPlatform() { return $this; } /** * 初始化开放平台账户 * @param string $config */ public function initWechatPlatformAccount($config = []) { $this->platformAppid = $config['app_id']; $this->platformAppsecret = $config['secret']; $this->platformEncodingaeskey = $config['aes_key']; $this->platformToken = $config['token']; $this->ticket = $this->getCache()->get('easywechat.open_platform.verify_ticket.' . $this->platformAppid); $accessToken = $this->app->access_token; $token = $accessToken->getToken(); $this->componentAccessToken = $token['component_access_token']; if (Cache::get('pre_auth_code') == false) { $this->getPreAuthCode(); } else { $this->preAuthCode = Cache::get('pre_auth_code'); } } public function SetVerifyTicket() { $verify_ticket = new VerifyTicket($this->app); try { $verify_ticket->getTicket(); } catch (\Exception $e) { $where = [['site_id', '=', 0], ['app_module', '=', 'admin'], ['config_key', '=', 'OPLATFORM_CONFIG']]; $info = model('config')->getValue($where, 'value'); if ($info) { $v = json_decode($info, true); $verify_ticket->setTicket($v['ComponentVerifyTicket'] ?? ''); } } } /** * 获取第三方平台的预授权码 需要第三方token,以及第三方appid */ private function getPreAuthCode() { $url = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=" . $this->componentAccessToken; $data = array('component_appid' => $this->platformAppid); $result = $this->apiPost($url, $data); if (!empty($result['pre_auth_code'])) { Cache::set('pre_auth_code', $result['pre_auth_code'], 500); $this->preAuthCode = Cache::get('pre_auth_code'); } } /** * 微信或小程序 网页授权后请求 * @param $url * @param $param * @param bool $needToken * @return array|mixed */ public function weappRequest($url, $param, $needToken = false, $method = 'post', $data_type = 'json') { // 第一次为空,则从文件中读取 if (empty($this->accessToken)) { $this->accessToken = Cache::get('accessToken-' . $this->appid); } // 为空则重新取值 if (empty($this->accessToken) or $needToken) { //开放平台网页授权 $this->getAccessTokenByWechatPlatform(); $this->accessToken = Cache::get('accessToken-' . $this->appid); } $new_url = sprintf($url, $this->accessToken); $result = $this->apiPost($new_url, $param, $method, 30, $data_type); if (!empty($result['errcode'])) { switch ($result['errcode']) { case 40001: return $this->weappRequest($url, $param, true); // 获取access_token时AppSecret错误,或者access_token无效 break; case 40014: return $this->weappRequest($url, $param, true); // 不合法的access_token break; case 42001: return $this->weappRequest($url, $param, true); // access_token超时 break; case 45009: return $this->error([], "接口调用超过限制:" . $result['errmsg']); break; case 41001: return $this->error([], "缺少access_token参数:" . $result['errmsg']); break; default: return $this->error($result, $this->error[abs($result['errcode'])] ?? $result['errmsg']); // 其他错误,抛出 break; } } else { return $this->success($result); } } /** * 通过上述方法获取的公众号access_token可能会过期,因此需要定时获取access_token */ public function getAccessTokenByWechatPlatform() { //获取公众号token $url = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=" . $this->componentAccessToken; $data = array( 'component_appid' => $this->platformAppid, 'authorizer_appid' => $this->appid, 'authorizer_refresh_token' => $this->refreshToken ); $result = $this->apiPost($url, $data); if ($result == false || empty($result)) { return $this->error(); } else { $token = $result['authorizer_access_token'] ?? ''; if (!empty($token)) { Cache::set('accessToken-' . $this->appid, $token, 3600); $this->accessToken = $token; } return $this->success(); } } /** * 远程接口调用 * @param $url * @param array $data * @return mixed */ public function apiPost($url, $data = [], $method = 'post', $timeout = 30, $data_type = 'json') { $curl = curl_init(); //创建一个新url资源 curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); if ($method == 'post') { if ($data_type == 'json') { $data = json_encode($data, JSON_UNESCAPED_UNICODE); } curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } curl_setopt($curl, CURLOPT_TIMEOUT, $timeout); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $ajax_return = curl_exec($curl); $code_arr = is_json($ajax_return) ? json_decode($ajax_return, true) : $ajax_return; return $code_arr; } /** * 获取代码模板列表 * @param array $param */ public function getTemplateList($param = [], $source_miniprogram_appid = 'wx10df35b8f8f07887') { $url = "https://api.weixin.qq.com/wxa/gettemplatelist?access_token=" . $this->componentAccessToken; $data = array(); $result = $this->apiPost($url, $data, 'GET'); if (isset($result['errcode']) && $result['errcode'] != 0) { return $this->error($result, $result["errmsg"]); } $template_list = []; if ($source_miniprogram_appid != '') { foreach ($result['template_list'] as $templateKey => $template) { if ($template['source_miniprogram_appid'] == $source_miniprogram_appid) { $template_list[] = $template; } } } else { $template_list = $result['template_list']; } return $this->success($template_list); } /** * 删除模板 * @param array $param * @return array */ public function deleteTemplate($param = []) { $url = "https://api.weixin.qq.com/wxa/deletetemplate?access_token=" . $this->componentAccessToken; $data = array( 'template_id' => $param['template_id'] ); $result = $this->apiPost($url, $data); if (isset($result['errcode']) && $result['errcode'] != 0) { return $this->error($result, $result["errmsg"]); } return $this->success($result); } /** * 获取开放平台代码模板列表 * @param array $param */ public function getDraftList($param = []) { $url = "https://api.weixin.qq.com/wxa/gettemplatedraftlist?access_token=" . $this->componentAccessToken; $data = array(); $result = $this->apiPost($url, $data); if (isset($result['errcode']) && $result['errcode'] != 0) { return $this->error($result, $result["errmsg"]); } return $this->success($result['draft_list']); } /** * 将草稿添加到代码模板库 * @param array $param * @return array */ public function addToTemplate($param = []) { $url = "https://api.weixin.qq.com/wxa/addtotemplate?access_token=" . $this->componentAccessToken; $data = array( 'draft_id' => $param['draft_id'] ); $result = $this->apiPost($url, $data); if (isset($result['errcode']) && $result['errcode'] != 0) { return $this->error($result, $result["errmsg"]); } return $this->success($result); } /** * 小程序代码上传 * 第三方平台需要先将草稿添加到代码模板库,或者中代码模板库中选取某个代码模板,得到对应的模板 id(template_id); 然后调用本接口可以为已授权的小程序上传代码。 * @param array $param * @return mixed */ public function weappCommit($param = []) { $url = "https://api.weixin.qq.com/wxa/commit?access_token=%s"; $ext_json = $param['ext_json'] ?? []; $data = array( 'template_id' => $param['template_id'] ?? '', 'ext_json' => json_encode($ext_json, JSON_UNESCAPED_UNICODE), 'user_version' => $param['user_version'] ?? '', 'user_desc' => $param['user_desc'] ?? '', ); $this->setDomain(); $result = $this->weappRequest($url, $data); if ($result['code'] < 0) { // 如果错误原因是“没有权限使用该插件”则去掉插件重新上传 if (isset($result['data']['errcode']) && $result['data']['errcode'] == 80082) { $ext_json['plugins'] = (object)array(); $data['ext_json'] = json_encode($ext_json, JSON_UNESCAPED_UNICODE); $result = $this->weappRequest($url, $data); if ($result['code'] < 0) return $result; } else { if (isset($result['data']["errmsg"])) { return $this->error([], $result['data']["errmsg"]); } return $this->error([], $result['message']); } } $where = [ 'template_id' => $param['template_id'] ?? '', 'status' => 6, 'site_id' => $ext_json['ext']['site_id'], 'version' => $param['user_version'], ]; $getID = model('weapp_audit_record')->getValue($where, 'id'); $audit_data = [ 'template_id' => $param['template_id'] ?? '', 'site_id' => $ext_json['ext']['site_id'], 'auditid' => '', 'version' => $param['user_version'], 'status' => 6, 'create_time' => time(), 'info' => json_encode($param), ]; if ($getID) { $res = model('weapp_audit_record')->update($audit_data, ['id' => $getID]); } else { $res = model('weapp_audit_record')->add($audit_data); } model('weapp_audit_record')->update(['status' => 7], [['site_id', '=', $audit_data['site_id']], ['status', '=', 6], ['version', '<>', $audit_data['version']]]); return $this->success($res); } /** * 小程序代码提交审核 * 在调用上传代码接口为小程序上传代码后,可以调用本接口,将上传的代码提交审核。 * @param array $param */ public function weappSubmitAudit($param = [], $id = '') { $url = "https://api.weixin.qq.com/wxa/submit_audit?access_token=%s"; $data = array( 'item_list' => $param['item_list'] ?? [],// 审核项列表(选填,至多填写 5 项) 'preview_info' => $param['preview_info'] ?? [],//预览信息(小程序页面截图和操作录屏) 'version_desc' => $param['version_desc'] ?? '',//小程序版本说明和功能解释 'feedback_info' => $param['feedback_info'] ?? '',//反馈内容,至多 200 字 'feedback_stuff' => $param['feedback_stuff'] ?? '',//用 | 分割的 media_id 列表,至多 5 张图片, 可以通过新增临时素材接口上传而得到 'order_path' => 'pages_market/order/list' ); $result = $this->weappRequest($url, $data); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } if ($id) { $datas = [ 'status' => 0, 'auditid' => $result['data']['auditid'] ]; model('weapp_audit_record')->update($datas, ['id' => $id]); } return $result; } /** * 获取体验版二维码 * @param array $param */ public function getQrcode() { $url = "https://api.weixin.qq.com/wxa/get_qrcode?access_token=%s"; $data = []; $result = $this->weappRequest($url, $data, false, 'get'); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } $upload = new Upload($this->site_id); $result = $upload->setPath('qrcode/platform/')->remotePullBinary($result['data']); return $result; } /** * 查询最新一次提交的审核状态 * @param array $param * @return array|mixed */ public function getLatestAuditstatus($param = []) { $url = "https://api.weixin.qq.com/wxa/get_latest_auditstatus?access_token=%s"; $data = array(); $result = $this->weappRequest($url, $data, false, 'get'); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /** * 查询指定发布审核单的审核状态 * 提交审核后,调用本接口可以查询指定发布审核单的审核状态 * @param array $param */ public function getAuditstatus($param = []) { $url = "https://api.weixin.qq.com/wxa/get_auditstatus?access_token=%s"; $data = array( 'auditid' => $param['auditid'] ?? '' ); $result = $this->weappRequest($url, $data); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /** * 审核撤回 * 调用本接口可以撤回当前的代码审核单 * 注意: 单个帐号每天审核撤回次数最多不超过 1 次,一个月不超过 10 次。 * @param array $param */ public function undocodeaudit($param = []) { $url = "https://api.weixin.qq.com/wxa/undocodeaudit?access_token=%s"; $data = array(); $result = $this->weappRequest($url, $data, false, 'get'); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /** * 发布已通过审核的小程序 * 调用本接口可以发布最后一个审核通过的小程序代码版本 * @return array|mixed */ public function release($param = []) { $url = "https://api.weixin.qq.com/wxa/release?access_token=%s"; $data = (object)array(); $result = $this->weappRequest($url, $data); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /** * 版本回退 * 调用本接口可以将小程序的线上版本进行回退 * 注意: * 如果没有上一个线上版本,将无法回退 * 只能向上回退一个版本,即当前版本回退后,不能再调用版本回退接口 * @param array $param */ public function revertcoderelease($param = []) { $url = "https://api.weixin.qq.com/wxa/revertcoderelease?access_token=%s"; $data = array(); $result = $this->weappRequest($url, $data, '', 'get'); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /*** * 设置系统必要域名 */ public function setDomain() { $dom = $this->modifyDomain(['action' => 'get']); if ($dom['code'] == 0) { $config_info = $this->openConfig; $post = [ 'requestdomain' => array_map(function ($v) { return 'https://' . $v; }, explode(';', $config_info['request_url'])), 'downloaddomain' => array_map(function ($v) { return 'https://' . $v; }, explode(';', $config_info['download_url'])), 'wsrequestdomain' => array_map(function ($v) { return 'wss://' . $v; }, explode(';', $config_info['socket_url'])), 'uploaddomain' => array_map(function ($v) { return 'https://' . $v; }, explode(';', $config_info['upload_url'])), ]; $push = false; $dom = $dom['data']; foreach ($post as $key => &$item) { if (isset($dom[$key])) { $item = array_values(array_diff($item, $dom[$key])); } if ($item) { $push = true; } } if ($push) { $post['action'] = 'add'; $this->modifyDomain($post); } } } /** * 设置服务器域名 * 授权给第三方的小程序,其服务器域名只可以为第三方平台的服务器,当小程序通过第三方平台发布代码上线后,小程序原先自己配置的服务器域名将被删除,只保留第三方平台的域名,所以第三方平台在代替小程序发布代码之前,需要调用接口为小程序添加第三方平台自身的域名。 * 注意: 需要先将域名登记到第三方平台的小程序服务器域名中,才可以调用接口进行配置。 * @param array $param */ public function modifyDomain($param = []) { $url = "https://api.weixin.qq.com/wxa/modify_domain?access_token=%s"; $data = array( 'action' => $param['action']//可选值 说明 add 添加 delete 删除 set 覆盖 get 获取 ); if ($param['action'] != 'get') { $data['requestdomain'] = $param['requestdomain']; $data['wsrequestdomain'] = $param['wsrequestdomain']; $data['uploaddomain'] = $param['uploaddomain']; $data['downloaddomain'] = $param['downloaddomain']; } $result = $this->weappRequest($url, $data); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /* * 添加体验者 * @param array $param * @return array|mixed */ public function bindTester($param = []) { $url = "https://api.weixin.qq.com/wxa/bind_tester?access_token=%s"; $data = [ 'wechatid' => $param['wechatid'] ]; $result = $this->weappRequest($url, $data); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /** * 解绑体验者 * @param array $param * @return array|mixed */ public function unbindTester($param = []) { $url = "https://api.weixin.qq.com/wxa/unbind_tester?access_token=%s"; $data = [ 'userstr' => $param['userstr'] ]; $result = $this->weappRequest($url, $data); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /*** * 获取隐私配置 * @param int $privacy_ver * @return array|mixed */ public function getPrivacysetting($privacy_ver = 2) { $privacy_ver = [ 'privacy_ver' => $privacy_ver ]; $url = "https://api.weixin.qq.com/cgi-bin/component/getprivacysetting?access_token=%s"; $result = $this->weappRequest($url, $privacy_ver); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } public function setPrivacysetting($setting_list, $owner_setting = [], $privacy_ver = 2) { if (!$owner_setting) { $owner_setting = [ 'contact_email' => '通过邮件发生通知信息', 'contact_phone' => '通过通过电话联系', 'contact_qq' => '通过QQ联系通知', 'contact_weixin' => '通过微信联系', 'notice_method' => '当平台发生信息变动时及时与客户联系沟通' ]; } $params = [ 'privacy_ver' => $privacy_ver, 'owner_setting' => $owner_setting, 'setting_list' => $setting_list, ]; $url = "https://api.weixin.qq.com/cgi-bin/component/setprivacysetting?access_token=%s"; $result = $this->weappRequest($url, $params); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /*** * 申请接口 * @param $key * @param $desc * @return array|mixed */ public function setPrivacyInterface($key, $desc, $pic_list = []) { $url = "https://api.weixin.qq.com/wxa/security/apply_privacy_interface?access_token=%s"; $data = [ 'api_name' => $key, 'content' => $desc, ]; if ($pic_list) { $data['pic_list'] = $pic_list; } $result = $this->weappRequest($url, $data); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result; } /*** * 获取接口权限状态 * @return array|mixed */ public function getPrivacyInterface() { $url = "https://api.weixin.qq.com/wxa/security/get_privacy_interface?access_token=%s"; $result = $this->weappRequest($url, [], false, 'get'); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result['data']; } /*** * 获取scheme码 * @return array|mixed */ public function getScheme($path = '', $query = '', $env_version = 'release') { $url = "https://api.weixin.qq.com/wxa/generatescheme?access_token=%s"; $result = $this->weappRequest($url, [ 'jump_wxa' => [ 'path' => $path, 'query' => $query, 'env_version' => $env_version, ], 'expire_type' => 0 ], TRUE); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result['data']; } /*** * 获取URLLink * @return array|mixed */ public function getURLLink($path = '', $query = '', $env_version = '') { $url = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=%s"; $result = $this->weappRequest($url, [ 'path' => $path, 'query' => $query, 'env_version' => $env_version, 'expire_type' => 0 ], TRUE); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result['data']; } public function getAccountBasicinfo() { $url = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo?access_token=%s"; $result = $this->weappRequest($url, []); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result['data']; } public function uploadImage($file) { $url = "https://api.weixin.qq.com/wxa/sec/uploadauthmaterial?access_token=%s"; $result = $this->weappRequest($url, [ 'media' => new \CURLFile($file) ], false, 'post', 'file'); if ($result['code'] == 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } } public function secwxaapiWxaauth($data) { $url = "https://api.weixin.qq.com/wxa/sec/wxaauth?access_token=%s"; $data['pay_type']=2; $data['account_name_type']=1; $data['third_party_phone']=config('wechat.component_phone'); $data['service_appid']=config('wechat.wxFuwu.appid'); // $data['qualification_other']=[]; //其他资料 $result = $this->weappRequest($url, $data); if ($result['code'] < 0) return $result; if (isset($result['data']['errcode']) && $result['data']['errcode'] != 0) { return $this->error($result, $result['data']["errmsg"]); } return $result['data']; } }