463 lines
14 KiB
PHP
Executable File
463 lines
14 KiB
PHP
Executable File
<?php
|
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
|
class Hd extends CI_Controller {
|
|
/**
|
|
* 版本控制
|
|
* 高版本写在前面
|
|
* 长的key写前面
|
|
* @var array
|
|
*/
|
|
private static $verison = array(
|
|
);
|
|
|
|
/**
|
|
* 应用ID
|
|
* @var array
|
|
*/
|
|
private static $apps = array(
|
|
'e49d182c6e6dab64' => 'liche',
|
|
'1c156bb57cd6984a' => 'licheb',
|
|
);
|
|
|
|
/**
|
|
* 错误信息映射到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 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'])){
|
|
// $data = _clean($data);//车亿宝列表需要list空数组判断
|
|
$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 .= $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;
|
|
}
|
|
|
|
// return true;
|
|
|
|
debug_log("[fail]". __FUNCTION__ . ": sign:{$sign}, check:{$string}, buff:{$buff}", $this->log_file);
|
|
return false;
|
|
}
|
|
|
|
}
|