'liche', '1c156bb57cd6984a' => 'licheb', 'fba9a12d2cd8599a' => 'neta', ); /** * 错误信息映射到lang,数字不能使用 */ private static $err_lang = array( API_CODE_SUCCESS => 'api_code_success', API_CODE_FAIL => 'api_code_fail', API_CODE_NONE => 'api_code_none', API_CODE_LOGOUT => 'api_code_logout', ); private $request; private $inputs; private $log_file = 'hd.log'; public function wxapp(){ $callback = $_GET['callback']; !$callback && $callback = $_POST['callback']; trim($callback);//去掉首尾空白符 $callback = $this->match_version($callback); $callback = explode('.', $callback); if(count($callback) > 2) { $method_name = array_pop($callback); $class_name = ucfirst(array_pop($callback)); $dir = implode('/', $callback); } else { echo 'inval request'; exit; } define('WECHATAPP', 1); $file_name = APPPATH."controllers/wxapp/{$dir}/{$class_name}.php"; if(file_exists($file_name)) { require_once $file_name; } else { echo "class {$class_name} not exist";exit; } if($class_name == 'Welcome') { $class = $this; } else { $class = new $class_name(); }; if(!$method_name || !method_exists($class, $method_name)) { echo "method {$method_name} not exist"; exit; }; try{ if(method_exists($class, 'check_login')){//校验登录 $class->check_login($method_name); } $result = $class->$method_name(); if(!$result) { throw new Exception('', ERR_SYS_FAIL); } $this->print_return($result); } catch (Exception $e) { $this->print_return($this->return_error($e->getCode(), $e->getMessage())); } } /** * 内容入口 */ function content(){ define('WXAPP_CONTENT', 1); //加载输入参数 $this->input_param(); $version = $this->input_param('version'); $sversion = $this->input_param('sversion'); $app_id = $this->input_param('app_id'); $this->log_file = get_class($this) . "_{$app_id}.log"; //卡ID为空 $app = self::$apps[$app_id]; if(!$app_id){ debug_log("[fail]". __FUNCTION__ . ":app_id is null; uri_string:" . $this->uri->uri_string(), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '应用不存在')); } //签名不正确 if(!$this->vaild_sign()){ debug_log("[fail]". __FUNCTION__ . ":sign check fail; uri_string:" . $this->uri->uri_string() . "; param:".json_encode($this->inputs), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '验签失败')); } $app = self::$apps[$app_id]; $class_name = ucfirst($this->uri->segment(3));//:hd/content/subject/tag if($this->uri->segment(4)){ $method = $this->request . "_" . $this->uri->segment(4); } else { $method = $this->request; } //app定制ct $file_name = APPPATH."controllers/wxapp/content/{$app}/{$class_name}.php"; //ct不存在 if(file_exists($file_name)) { require_once $file_name; } else { //app定制ct不存在,使用公共ct $file_name = APPPATH."controllers/wxapp/content/{$class_name}.php"; if(file_exists($file_name)) { require_once $file_name; } else{ debug_log("[fail]". __FUNCTION__ . ": file '{$file_name}' not exist; method:{$method}, app_id:".$app_id, $this->log_file); return $this->print_return($this->return_error(API_CODE_NONE, '内部错误')); } } try{ $class = new $class_name($this->inputs, $app); $result = $class->$method($version, $sversion); if(!$result) { throw new Exception('', ERR_SYS_FAIL); } return $this->print_return($result); } catch (Exception $e){ return $this->print_return($this->return_error($e->getCode(), $e->getMessage())); } } /** * app其他入口 */ function app(){ define('WXAPP_APP', 1); //加载输入参数 $this->input_param(); $app_id = $this->input_param('app_id'); $version = $this->input_param('version'); $sversion = $this->input_param('sversion'); $this->log_file = get_class($this) . "_{$app_id}.log"; $app = self::$apps[$app_id]; $dir = $app; //卡ID为空 if(!$app_id){ debug_log("[fail]". __FUNCTION__ . ": app_id is null; uri_string:" . $this->uri->uri_string(), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '应用不存在'.$app_id)); } //签名不正确 if(!$this->vaild_sign()){ debug_log("[fail]". __FUNCTION__ . ": sign check fail; uri_string:" . $this->uri->uri_string() . "; param:".json_encode($this->inputs), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '验签失败')); } $class_name = ucfirst($this->uri->segment(3));//:hd/app/user/ukey if($this->uri->segment(4)){ $method = $this->request . "_" . $this->uri->segment(4); } else { $method = $this->request; } //app定制ct $file_name = APPPATH."controllers/wxapp/{$app}/{$class_name}.php"; //ct不存在 if(file_exists($file_name)) { require_once $file_name; } else { $file_name = APPPATH."controllers/wxapp/app/{$dir}/Self_{$class_name}.php"; if(file_exists($file_name)){ require_once $file_name; $class_name = "Self_{$class_name}"; } else { //app定制ct不存在,使用公共ct $file_name = APPPATH."controllers/wxapp/app/{$class_name}.php"; if(file_exists($file_name)) { require_once $file_name; } else{ debug_log("[fail]". __FUNCTION__ . ": file '{$file_name}' not exist; method:{$method}, app_id:".$app_id, $this->log_file); return $this->print_return($this->return_error(API_CODE_NONE, '内部错误')); } } } try{ $class = new $class_name($this->inputs, $app); $result = $class->$method($version, $sversion); if(!$result) { throw new Exception('', ERR_SYS_FAIL); } return $this->print_return($result); } catch (Exception $e){ return $this->print_return($this->return_error($e->getCode(), $e->getMessage())); } } /** * 分销入口 */ public function distribution(){ define('WXAPP_ITEMS', 1); //加载输入参数 $this->input_param(); $app_id = $this->input_param('app_id'); !$app_id && $app_id = $this->input_param('vipcard_id'); $version = $this->input_param('version'); $sversion = $this->input_param('sversion'); $this->log_file = get_class($this) . "_{$app_id}.log"; //应用ID为空 if(!$app_id){ debug_log("[fail]". __FUNCTION__ . ":app_id is null; uri_string:" . $this->uri->uri_string(), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '请求丢失')); } //签名不正确 if(!$this->vaild_sign()){ debug_log("[fail]". __FUNCTION__ . ":sign check fail; uri_string:" . $this->uri->uri_string() . "; param:".json_encode($this->inputs), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '非法请求')); } $app = self::$apps[$app_id]; $class_name = ucfirst($this->uri->segment(3)); if($this->uri->segment(4)){ $method = $this->request . "_" . $this->uri->segment(4); } else { $method = $this->request; } //app定制ct $file_name = APPPATH."controllers/wxapp/distribution/{$app}/{$class_name}.php"; //ct不存在 if(file_exists($file_name)) { require_once $file_name; } else { //app定制ct不存在,使用公共ct $file_name = APPPATH."controllers/wxapp/distribution/{$class_name}.php"; if(file_exists($file_name)) { require_once $file_name; } else{ debug_log("[fail]". __FUNCTION__ . ": file '{$file_name}' not exist; method:{$method}, app_id:".$app_id, $this->log_file); return $this->print_return($this->return_error(API_CODE_NONE, '非法请求')); } } try{ $class = new $class_name($this->inputs, $app); $result = $class->$method($version, $sversion); if(!$result) { throw new Exception('', ERR_SYS_FAIL); } return $this->print_return($result); } catch (Exception $e){ return $this->print_return($this->return_error($e->getCode(), $e->getMessage())); } } /** * 博饼入口 */ public function bobing() { define('WXAPP_ITEMS', 1); //加载输入参数 $this->input_param(); $app_id = $this->input_param('app_id'); !$app_id && $app_id = $this->input_param('vipcard_id'); $version = $this->input_param('version'); $sversion = $this->input_param('sversion'); $this->log_file = get_class($this) . "_{$app_id}.log"; //应用ID为空 if (!$app_id) { debug_log("[fail]" . __FUNCTION__ . ":app_id is null; uri_string:" . $this->uri->uri_string(), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '请求丢失')); } //签名不正确 if (!$this->vaild_sign()) { debug_log("[fail]" . __FUNCTION__ . ":sign check fail; uri_string:" . $this->uri->uri_string() . "; param:" . json_encode($this->inputs), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '非法请求')); } $app = self::$apps[$app_id]; $class_name = ucfirst($this->uri->segment(3)); if ($this->uri->segment(4)) { $method = $this->request . "_" . $this->uri->segment(4); } else { $method = $this->request; } //app定制ct $file_name = APPPATH . "controllers/wxapp/bobing/{$app}/{$class_name}.php"; //ct不存在 if (file_exists($file_name)) { require_once $file_name; } else { //app定制ct不存在,使用公共ct $file_name = APPPATH . "controllers/wxapp/bobing/{$class_name}.php"; if (file_exists($file_name)) { require_once $file_name; } else { debug_log("[fail]" . __FUNCTION__ . ": file '{$file_name}' not exist; method:{$method}, app_id:" . $app_id, $this->log_file); return $this->print_return($this->return_error(API_CODE_NONE, '非法请求')); } } try { $class = new $class_name($this->inputs, $app); $result = $class->$method($version, $sversion); if (!$result) { throw new Exception('', ERR_SYS_FAIL); } return $this->print_return($result); } catch (Exception $e) { return $this->print_return($this->return_error($e->getCode(), $e->getMessage())); } } /** * 推广素材入口 */ public function material() { define('WXAPP_ITEMS', 1); //加载输入参数 $this->input_param(); $app_id = $this->input_param('app_id'); !$app_id && $app_id = $this->input_param('vipcard_id'); $version = $this->input_param('version'); $sversion = $this->input_param('sversion'); $this->log_file = get_class($this) . "_{$app_id}.log"; //应用ID为空 if (!$app_id) { debug_log("[fail]" . __FUNCTION__ . ":app_id is null; uri_string:" . $this->uri->uri_string(), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '请求丢失')); } //签名不正确 if (!$this->vaild_sign()) { debug_log("[fail]" . __FUNCTION__ . ":sign check fail; uri_string:" . $this->uri->uri_string() . "; param:" . json_encode($this->inputs), $this->log_file); return $this->print_return($this->return_error(API_CODE_INVILD_PARAM, '非法请求')); } $app = self::$apps[$app_id]; $class_name = ucfirst($this->uri->segment(3)); if ($this->uri->segment(4)) { $method = $this->request . "_" . $this->uri->segment(4); } else { $method = $this->request; } //app定制ct $file_name = APPPATH . "controllers/wxapp/material/{$app}/{$class_name}.php"; //ct不存在 if (file_exists($file_name)) { require_once $file_name; } else { //app定制ct不存在,使用公共ct $file_name = APPPATH . "controllers/wxapp/material/{$class_name}.php"; if (file_exists($file_name)) { require_once $file_name; } else { debug_log("[fail]" . __FUNCTION__ . ": file '{$file_name}' not exist; method:{$method}, app_id:" . $app_id, $this->log_file); return $this->print_return($this->return_error(API_CODE_NONE, '非法请求')); } } try { $class = new $class_name($this->inputs, $app); $result = $class->$method($version, $sversion); if (!$result) { throw new Exception('', ERR_SYS_FAIL); } return $this->print_return($result); } catch (Exception $e) { return $this->print_return($this->return_error($e->getCode(), $e->getMessage())); } } /** * 测试签名(开发环境) */ public function test_sign(){ if(false === strpos($_SERVER['SERVER_NAME'], 'dev')){ exit('forbidden'); } //加载输入参数 $this->input_param(); $param = $this->inputs; $app_id = $param['app_id']; !$app_id && $app_id = $param['vipcard_id']; $sign = strtoupper($param['sign']); $nonce_str = $param['nonce_str']; unset($param['sign']); if(!$app_id || !$sign || !$nonce_str){ exit(json_encode($param)); } //根据biz_id 获取key $app = self::$apps[$app_id]; $this->config->load('app', true, true); $configs = $this->config->item('app'); $config = $configs[$app]; $key = $config['sign_key']; //按字典序排序参数 ksort($param); $buff = ""; foreach($param as $k => $v){ if(!is_array($v) && strlen($v) > 0){ // $buff .= $k . "=" . $v . "&"; $buff .= $k . "=" . ($v) . "&"; } } $buff = trim($buff, "&"); //在string后加入KEY $buff = $buff . "&key=" . $key; //MD5加密并转大写 $string = strtoupper(md5($buff)); // if($sign == $string){ // return true; // } $res = array('sign_input' => $sign, 'sign_output' => $string, 'buff' => $buff); exit(json_encode($res)); } /** * 可能要被废弃 * @param $err_code * @param string $err_info * @return array */ function error_msg($err_code, $err_info = "") { if(!$err_info) { $this->lang->load('error_lang','zh'); $err_info = $this->lang->line(self::$err_lang[$err_code], false); } return array('errCode' => $err_code, 'errMessage' => $err_info); } /** * 打印返回值 * @param array $data * @param bool $ifgzip */ private function print_return($data = array(), $ifgzip = false){ if(!isset($data['code'])){ $msg = $data['msg'] ? $data['msg'] : '执行成功'; $data = array('code' => 200, 'data' => $data, 'msg' => $msg); } if($ifgzip) { header('Content-Type: application/json'); header('Content-Encoding: gzip'); echo gzencode(json_encode($data, JSON_UNESCAPED_UNICODE), 6); exit; } else { $result = json_encode($data, JSON_UNESCAPED_UNICODE); echo $result; exit; } } /** * 根据错误码输出 * @param $code * @param string $msg * @return array */ private function return_error($code, $msg = ''){ if(!$msg) { $this->lang->load('error_lang','zh'); $msg = $this->lang->line(self::$err_lang[$code], false); } return array('code' => $code, 'msg' => $msg); } /** * 匹配版本url * @param $callback * @param string $version * @return mixed */ private function match_version($callback, $version = ''){ $version_group = self::$verison; $ver_arr = $version_group[$callback]; $ck = $callback; if(!$ver_arr){ foreach($version_group as $k => $arr){ if(0 === strpos($callback, $k)){ $ver_arr = $arr; $ck = $k; break; } } } if($ver_arr){ if(!$version){ $cv = reset($ver_arr); } else { foreach($ver_arr as $k => $v){ $cmp = $this->vercmp($version, $k); if($cmp >= 0){ $cv = $v; break; } } } } if(isset($cv)){ $callback = str_replace($ck, $cv, $callback); } return $callback; } /** * 比较版本号 * @param $ver1 * @param $ver2 * @return int 1:$ver1 > $ver2; -1:$ver1 < $ver2; 0:$ver1 == $ver2; */ private function vercmp($ver1, $ver2){ $v1_arr = explode('.', $ver1); $v2_arr = explode('.', $ver2); foreach($v1_arr as $k => $v){ $sub = $v - $v2_arr[$k]; if(0 != $sub){ return $sub > 0 ? 1 : -1; } } return 0; } /** * 获取参数 * @param string $key * @return array|mixed */ private function input_param($key = ''){ if($key){ return $this->inputs[$key]; } $request = $this->input->method(); switch($request){ case 'post': case 'put': case 'delete': $input = json_decode(file_get_contents('php://input'), true); break; default: $input = $this->input->get(); } $this->request = $request; $this->inputs = $input; return $this->inputs; } /** * 校验签名 * @return bool */ private function vaild_sign(){ $param = $this->inputs; $app_id = $param['app_id']; !$app_id && $app_id = $param['vipcard_id']; $sign = strtoupper($param['sign']); $nonce_str = $param['nonce_str']; unset($param['sign']); if(!$app_id || !$sign || !$nonce_str){ debug_log("[fail]". __FUNCTION__ . ": not app_id, sign, nonce_str", $this->log_file); return false; } //根据biz_id 获取key $app = self::$apps[$app_id]; $this->config->load('app', true, true); $configs = $this->config->item('app'); $config = $configs[$app]; $key = $config['sign_key']; //按字典序排序参数 ksort($param); $buff = ""; foreach($param as $k => $v){ if(!is_array($v) && strlen($v) > 0){ $buff .= $k . "=" . ($v) . "&"; } } $buff = trim($buff, "&"); //在string后加入KEY $buff = $buff . "&key=" . $key; //MD5加密并转大写 $string = strtoupper(md5($buff)); //var_dump($string); //var_dump($buff); if($sign == $string){ return true; } debug_log("[fail]". __FUNCTION__ . ": sign:{$sign}, check:{$string}, buff:{$buff}", $this->log_file); return false; } /** * 上传图片 * @throws Exception */ public function upimg(){ $app = $this->input->post('app'); $log_name = "{$app}_upimg.log"; try { if(!$app){ throw new Exception('参数错误', API_CODE_INVILD_PARAM); } //接收图片 if (!$file = $_FILES['img']) { throw new Exception('请选择图片', API_CODE_INVILD_PARAM); } if (!$file['tmp_name']) {//太大的图片上传,这个参数会变成空的 debug_log(json_encode($file), $log_name); throw new Exception('参数错误', API_CODE_INVILD_PARAM); } debug_log("[info]". __FUNCTION__ . ": tmp_name:" . $file['tmp_name'] . ";size:" . filesize($file['tmp_name']), $log_name); if (!file_exists(TEMP_PATH)){ $oldumask = umask(0); mkdir(TEMP_PATH, 0777, true); umask($oldumask); } $tmp = TEMP_PATH . md5($file['name'] . uniqid()) . substr($file['name'], strpos($file['name'], '.', strlen($file['name']) - 1)); move_uploaded_file($file['tmp_name'], $tmp); debug_log("[info]". __FUNCTION__ . "tmp:$tmp;size:" . filesize($tmp), $log_name); if (!filesize($tmp)) { throw new Exception('图片有点问题,换个小的试试', API_CODE_INVILD_PARAM); } //上传图片到FTP $res = $this->upload_img_qiniu($tmp,"{$app}/"); if (!$res) { throw new Exception('上传失败', API_CODE_FAIL); } $data['full_url'] = build_qiniu_image_url($res['photo']); $data['url'] = $res['photo']; debug_log("[info]". __FUNCTION__ . "full_url:" . $data['full_url'], $log_name); $this->print_return($data); } catch (Exception $e) { $message = $e->getMessage(); $this->print_return($this->return_error($e->getCode(), $message)); } } /** * @param string $file 上传的文件 * @param string $path 要保存的目录 * @param string $filename 原始文件名称 * @throws Exception * @return array */ private function upload_img_qiniu($file, $path = '',$filename = ''){ $phoId = md5(uniqid().mt_rand(0,10000).time()); $filename = $filename ? $filename : $file; $ext_arr = explode(".", $filename); $ext = count($ext_arr)>1?$ext_arr[count($ext_arr)-1]:'jpg'; if (is_uploaded_file($file)) { //上传图片 $oriPath = TEMP_PATH . '/p_' . $phoId . '_ori.' . $ext; move_uploaded_file($file, $oriPath); } else { $oriPath = $file; } $oriKey = 'p_' . $phoId . '.' . $ext; // 上传到七牛后保存的文件名 $photo = $path .date('Ym') . "/" . $oriKey; //上传图片到FTP $this->load->library('qiniu'); $res= $this->qiniu->save($photo, file_get_contents($oriPath)); $img_size = getimagesize($oriPath); $file_size = filesize($oriPath); $size = "{$img_size[0]},{$img_size[1]},{$file_size}"; unlink($oriPath); if ($res) { $size = getimagesize($res['url']); return array('photo' => $res['file'], 'size' => $size); } else { return array(); } } }