diff --git a/app/api/controller/v1/User.php b/app/api/controller/v1/User.php index 26b4f3d..e6f2719 100644 --- a/app/api/controller/v1/User.php +++ b/app/api/controller/v1/User.php @@ -19,7 +19,9 @@ class User extends ApiController ->where('user_id', input('user_id')) // ->whereNotNull('delete_time') ->find(); - + if(!$user){ + return $this->error('SSO用戶不存在'); + } return $this->success($user); } catch (\Exception $e) { return $this->error('操作失敗'); diff --git a/app/appapi/ApiController.php b/app/appapi/ApiController.php new file mode 100644 index 0000000..ae1a0b0 --- /dev/null +++ b/app/appapi/ApiController.php @@ -0,0 +1,130 @@ +app = $app; + $this->request = $this->app->request; + + // 控制器初始化 + $this->initialize(); + } + + // 初始化 + protected function initialize() + { + header('Access-Control-Allow-Origin: *'); + // //允許的請求頭信息 + header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization"); + // //允許的請求類型 + header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH'); + + header('Access-Control-Expose-Headers: authorization'); + + // //允許攜帶證書式訪問(攜帶cookie) + header('Access-Control-Allow-Credentials:true'); + + $this->uid = input('uid'); + } + + /** + * 验证数据 + * @access protected + * @param array $data 数据 + * @param string|array $validate 验证器名或者验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array|string|true + * @throws ValidateException + */ + protected function validate(array $data, $validate, array $message = [], bool $batch = false) + { + if (is_array($validate)) { + $v = new Validate(); + $v->rule($validate); + } else { + if (strpos($validate, '.')) { + // 支持场景 + [$validate, $scene] = explode('.', $validate); + } + $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate); + $v = new $class(); + if (!empty($scene)) { + $v->scene($scene); + } + } + + $v->message($message); + + // 是否批量验证 + if ($batch || $this->batchValidate) { + $v->batch(true); + } + + return $v->failException(true)->check($data); + } + + public function Success($data,$code=200,$message='請求成功',$type='json',$header=[]){ + $result = [ + 'code' => $code, + 'message' => $message, + 'time'=>time(), + 'data'=>$data + ]; + return Response::create($result,$type)->header($header); + } + + public function Error($data,$code=500,$message='請求失敗',$type='json',$header=[]){ + $result = [ + 'code' => $code, + 'message' => $message, + 'time'=>time(), + 'data'=>$data + ]; + return Response::create($result,$type)->header($header); + } +} diff --git a/app/appapi/controller/v1/Auth.php b/app/appapi/controller/v1/Auth.php new file mode 100644 index 0000000..95c7f8a --- /dev/null +++ b/app/appapi/controller/v1/Auth.php @@ -0,0 +1,337 @@ +parse($id_token); + // print_r($token->getClaim('name')); + + //驗證id_token + + + $user=Db::name('user') + ->where('line_id',$line_id) + ->find(); + + if(!$user){ + return $this->success('非會員',201); + } + + + $token = JWTAuth::builder( + [ + 'id' => $user['id'], + 'user_id' => $user['user_id'], + 'level' => $user['level'] + ]); + + + + if(empty($user['uniqid'])){ + return $this->success(['uid'=>$user['user_id'],'token'=>'Bearer '.$token],202); + } + + return $this->success(['uid'=>$user['user_id'],'token'=>'Bearer '.$token]); + } + + public function bindCard(){ + $uid = input('uid'); + $verify = input('verify'); + + try{ + Db::name('user') + ->where('user_id',$uid) + ->update(['uniqid'=>$verify]); + + Db::name('precard') + ->where('verify_code',$verify) + ->update(['status'=>2]); + + return $this->success('綁定成功'); + }catch(\Exception $e){ + return $this->error('綁定失敗'); + } + + } + + public function checkLineId(){ + $line_id=input('lineid'); + + $user = Db::name('user') + ->where('line_id',$line_id) + ->find(); + + if($user){ + return $this->error('會員已存在'); + } + + return $this->success('檢查成功'); + } + + public function register(){ + $data = input(); + + unset($data['version']); + unset($data['controller']); + unset($data['action']); + unset($data['uid']); + unset($data['userid']); + unset($data['verify']); + unset($data['token']); + + $data=array_map('asc_trim',$data); + + //檢查line id是否己經是會員 + //TODO + $user=Db::name('user') + ->where('line_id',input('line_id')) + ->find(); + + if($user){ + return $this->error('已是會員',501); + } + + + //驗證id_token + $verify_line = $this->verifyIdToken(input('token')); + + if(!$verify_line){ + return $this->error('id token expire',500); + } + + + $data['line_name'] = $verify_line['name']; + $data['line_picture'] = $verify_line['picture']; + + //推薦人 + // if(strlen($data['refer'])>0){ + // $pid = decodeRefer($data['refer']); + // $data['parent_id'] = $pid; + // }else{ + // $data['parent_id'] = 0; + // } + // unset($data['refer']); + + if(input('verify')){ + $action = 'openright'; + + $user_id=genUniqid(); + $data['user_id'] = $user_id; + + $data['uniqid'] = input('verify'); + + $precard = Db::name('precard') + ->where('verify_code',input('verify')) + ->find(); + + if(!$precard){ + return $this->error('查無預開卡',401); + } + + $data['agent_id'] = $precard['agent_id']; + //TODO + }else{ + $action = 'register'; + if(!isset($data['aid'])){ + $data['agent_id'] = 1; + }else{ + $data['agent_id'] = Db::name('agent')->where('prefix',$data['aid'])->value('id'); + unset($data['aid']); + } + + $user_id=genUniqid(); + $data['user_id'] = $user_id; + } + + $avatar=$this->saveLineImage($data['line_picture'],$data['user_id']); + $data['line_picture']= getUrl().'/storage/'.$data['user_id'].'/'.$avatar; + + if(!isset($data['avatar'])){ + $data['avatar']=$data['line_picture']; + }else{ + $file_path = $_SERVER['DOCUMENT_ROOT'].'/storage/'.$data['user_id'].'/'.date('Ymd').'/'; + if(!is_dir($file_path)){ + mkdir($file_path, 0777, true); + } + $temp_file = str_replace(getUrl(),"",$data['avatar']); + $avatar_file = $file_path.basename($temp_file); + if(!rename($_SERVER['DOCUMENT_ROOT'].$temp_file, $avatar_file)){ + return $this->error('搬移檔案失敗'); + } + $data['avatar']=getUrl().'/storage/'.$data['user_id'].'/'.date('Ymd').'/'.basename($temp_file); + } + + $agent = Db::name('agent')->where('id',$data['agent_id'])->find(); + + if($agent['try_days']==0){ + $data['status'] = 1; + $data['level'] = $agent['base_level']; + $data['overdue_time'] = strtotime(date('Y-m-d',time() + (60 * 60 * 24 * $agent['base_days']))); + }else{ + $data['status'] = 2; + $data['level'] = $agent['try_level']; + $data['overdue_time'] = strtotime(date('Y-m-d',time() + (60 * 60 * 24 * $agent['try_days']))); + } + + if($agent['parent_id']==0){ + $data['agent_id'] = $agent['id']; + }else{ + $data['agent_id'] = $agent['parent_id']; + } + + $level_option = Db::name('user_level') + ->where('agent_id',$data['agent_id']) + ->where('level_id',$data['level']) + ->find(); + + $data['nc_type']=$level_option['nc_type']; + $data['nc_func']=$level_option['nc_func']; + + $data['cus_card'] = ''; + $data['create_time'] = date('Y-m-d H:i:s'); + + + try{ + $id = Db::name('user') + ->insertGetId($data); + + $refer_code = encodeRefer($id); + + + $result = Db::name('user') + ->where('id',$id) + ->update(['code'=>$refer_code]); + + + $qrcodeUrl = genQrCode('https://'.$_SERVER['HTTP_HOST'].'/home/?aid='.$agent['prefix'],$data['user_id'],'refer'); + + $aes = new Aes([]); + + $params = urlencode($aes->encrypt('user_id='.$data['user_id'].'&verify_code='.input('verify'))); + + $nfcUrl = genQrCode('https://'.$_SERVER['HTTP_HOST'].'/card/?params='.$params,$data['user_id'],'nfc'); + + Vcard::genVcf($data['user_id']); + + $token = JWTAuth::builder( + [ + 'id' => $id, + 'user_id' => $data['user_id'], + 'level' => 0 + ]); + + if($action == 'openright'){ + Db::name('precard') + ->where('verify_code',input('verify')) + ->update(['status'=>2]); + } + + return $this->success(['uid'=>$data['user_id'],'token'=>'Bearer'.$token]); + + }catch(\Exception $e){ + print_r($e); + return $this->error('註冊失敗'); + } + + } + + private function verifyIdToken($token){ + try{ + $client = new Client(); + $response = $client->request('POST', 'https://api.line.me/oauth2/v2.1/verify', [ + 'form_params' => [ + 'id_token' => $token, + 'client_id'=> env('utel.line_channel_id') + ] + ]); + + $body = $response->getBody()->getContents(); + return json_decode($body, true); + + } catch (\Exception $e) { + return false; + } + + // print_r($response); + // $body = $response->getBody()->getContents(); + + // print_r($body); + + } + + private function saveLineImage($pictureUrl,$uid) + { + if($pictureUrl){ + $curl = curl_init($pictureUrl); + curl_setopt($curl,CURLOPT_RETURNTRANSFER,1); + $imageData=curl_exec($curl); + curl_close($curl); + + $filename=$uid."_line.jpg"; + $filedir=$_SERVER['DOCUMENT_ROOT'].'/storage/'.$uid; + if (!file_exists($filedir)) { + mkdir($filedir , 0777 , true); + } + $fp=fopen($filedir.'/'.$filename,'a'); + fwrite($fp,$imageData); + fclose($fp); + + return $filename; + }else{ + return false; + } + } + + public function getSiteConfig(){ + $result = Db::name('site_config') + ->where('parent_id','<>',0) + ->select(); + + foreach($result as $key => $val){ + $rtn[$val['code']]=$val['value']; + } + + return $this->success($rtn); + } + + public function uploadAvatar(){ + + $files = request()->file('file'); + $savename = \think\facade\Filesystem::disk('public')->putFile( 'temp' , $files); + + $avatar = getUrl().'/storage/'.$savename; + + + // Db::name('user') + // ->where('user_id',input('user_id')) + // ->update(['avatar'=>$avatar]); + + return $this->Success($avatar); + } + + public function test(){ + Vcard::genVcf('mc63de2a162b218'); + } +} diff --git a/app/appapi/controller/v1/Card.php b/app/appapi/controller/v1/Card.php new file mode 100644 index 0000000..efdd21f --- /dev/null +++ b/app/appapi/controller/v1/Card.php @@ -0,0 +1,246 @@ + + * + * @param string token 加密參數 + * + * @return json + */ + public function checkUser(){ + $token = input('token'); + + if(!$token){ + return $this->error('參數錯誤'); + } + + $aes = new Aes([]); + parse_str($aes->descrypt($token),$params); + + if(!isset($params['verify_code'])){ + if(!isset($params['user_id'])){ + return $this->error('參數錯誤'); + } + $user_id = $params['user_id']; + }else{ + if(strlen($params['verify_code'])>0){ + $user_id = getUseridByCuid(strtoupper($params['verify_code'])); + }else{ + return $this->error('參數錯誤'); + } + } + + + if($user_id){ + Db::name('user') + ->where('user_id',$user_id) + ->inc('nfc_count') + ->update(); + + return $this->success($user_id); + } + + //檢查是否為預開卡會員 + $is_precard=Db::name('precard') + ->where('verify_code',strtoupper($params['verify_code'])) + ->count(); + + + if($is_precard){ + return $this->success(['verify'=>strtoupper($params['verify_code'])],201); + } + + return $this->error('請求錯誤'); + } + + public function getCard(){ + $do=Db::name('user'); + + if(input('userid')){ + $do->where('user_id',input('userid')); + }elseif(input('line_id')){ + $do->where('line_id',input('line_id')); + }else{ + return $this->error('查無會員資料'); + } + + + $user = $do->find(); + if(!$user){ + return $this->error('查無會員資料'); + } + + $aes = new Aes([]); + + if(strlen($user['uniqid'])>0){ + $params = urlencode($aes->encrypt('verify_code='.$user['uniqid'])); + }else{ + $params = urlencode($aes->encrypt('user_id='.$user['user_id'])); + } + + $user['nfcurl'] = getUrl().'/card/?params='.$params; + + + $result = [ + "address" => $user['address']?$user['address']:' ', + "company" => $user['company']?$user['company']:' ', + "email" => $user['email']?$user['email']:' ', + "logo" => "https://i.imgur.com/GclvYFK.png", + "maps" => "https://www.google.com/maps/search/?api=1&query_place_id=ChIJAaZEqCYWaTQRMv6fuIsJEuo&query=%E5%BE%AE%E7%A8%8B%E5%BC%8F%E8%B3%87%E8%A8%8A&openExternalBrowser=1", + "name" => $user['real_name']?$user['real_name']:' ', + "phone" => $user['phone']?$user['phone']:' ', + "tel" => $user['tel']?$user['tel']:' ', + "title" => $user['title']?$user['title']:' ', + "url" => $user['url']?$user['url']:' ', + "line" => $user['line']?$user['line']:'', + "facebook" => $user['facebook']?$user['facebook']:'', + "youtube" => $user['youtube']?$user['youtube']:'', + "ig" => $user['ig']?$user['ig']:'', + "level" => $user['level']?$user['level']:0, + "user_id" => $user['user_id']?$user['user_id']:'', + "line_picture" => $user['line_picture']?$user['line_picture']:'', + "avatar" => $user['avatar']?$user['avatar']:'', + "card_title" => $user['card_title']?$user['card_title']:'', + "has_cuscard" => strlen($user['cus_card'])?1:0, + "nc_type" => $user['nc_type']?$user['nc_type']:0, + "nc_func" => explode(',',$user['nc_func']), + "nc_template" => $user['nc_template'], + "mark" => nl2br($user['mark']), + "nfcurl" => $user['nfcurl'], + "show_cus" => $user['show_cus'], + "nfc_addon" => json_decode($user['nfc_addon']) + ]; + + + return $this->Success($result); + } + + public function getCusCard(){ + $data=input(); + unset($data['version']); + unset($data['controller']); + unset($data['action']); + + try{ + + $do=Db::name('user'); + if(input('userid')){ + $do->where('user_id',input('userid')); + }elseif(input('line_id')){ + $do->where('line_id',input('line_id')); + }else{ + return $this->error('查無會員資料'); + } + + $card = $do->field('cus_card,card_title') + ->find(); + + + }catch(Exception $e){ + return $this->error('操作失敗'); + } + return $this->success($card); + } + + public function getVipCard(){ + $data=input(); + unset($data['version']); + unset($data['controller']); + unset($data['action']); + + try{ + $do=Db::name('user_card'); + if(input('userid')){ + $id = getIdByUid(input('userid')); + }elseif(input('line_id')){ + $id = getIdByUid(input('lineid')); + }else{ + return $this->error('查無會員資料'); + } + $do->where('user_id',$id); + $card = $do->field('*') + ->select(); + + }catch(Exception $e){ + return $this->error('操作失敗'); + } + return $this->success($card); + } + + public function updateCard(){ + $data=input(); + unset($data['uid']); + unset($data['version']); + unset($data['controller']); + unset($data['action']); + unset($data['nfcurl']); + unset($data['agent_prefix']); + unset($data['level_name']); + unset($data['addon']); + unset($data['delete_time']); + + if(!empty(input('addon'))){ + $data['nfc_addon']=json_encode(input('addon')); + }else{ + $data['nfc_addon']=''; + } + + try{ + Db::name('user') + ->where('user_id',$data['user_id']) + ->update($data); + + Vcard::genVcf($data['user_id']); + + + }catch(Exception $e){ + return $this->error('操作失敗'); + } + return $this->success(['code'=>200]); + } + + public function updateCusCard(){ + + $data=input(); + unset($data['version']); + unset($data['controller']); + unset($data['action']); + + $data['show_cus'] = input('show_cus')?1:0; + + try{ + Db::name('user') + ->where('user_id',$data['user_id']) + ->update(['card_title'=>$data['card_title'],'show_cus'=>$data['show_cus'],'cus_card'=>$data['cus_card']]); + + }catch(Exception $e){ + return $this->error('操作失敗'); + } + return $this->success(['code'=>200]); + } + + + public function uploadFile(){ + // print_r(input()); + $files = request()->file('file'); + + $savename = \think\facade\Filesystem::disk('public')->putFile( 'card', $files);; + + $image_url = getUrl().'/storage/'.$savename; + + return $this->success($image_url); + } + +} diff --git a/app/appapi/controller/v1/User.php b/app/appapi/controller/v1/User.php new file mode 100644 index 0000000..9fcd364 --- /dev/null +++ b/app/appapi/controller/v1/User.php @@ -0,0 +1,82 @@ +where('user_id',$this->uid) + ->find(); + + $aes = new Aes([]); + if(strlen(trim($user['uniqid']))>0){ + $params = urlencode($aes->encrypt('verify_code='.$user['uniqid'])); + }else{ + $params = urlencode($aes->encrypt('user_id='.$user['user_id'])); + } + + $user['level_name'] = Db::name('user_level')->where('agent_id',$user['agent_id'])->where('level_id',$user['level'])->value('name'); + + $user['nfcurl'] = getUrl().'/card/?params='.$params; + + $user['nc_func'] = explode(',',$user['nc_func']); + + $user['agent_prefix'] = Db::name('agent')->where('id',$user['agent_id'])->value('prefix'); + + return $this->Success($user); + } + + public function setUserLevel(){ + $result=Db::name('user') + ->where('user_id',$this->uid) + ->update(['level'=>input('level')]); + + + return $this->Success($result); + } + + public function setUserTpl(){ + try{ + $result=Db::name('user') + ->where('user_id',$this->uid) + ->update(['nc_template'=>input('tpl')]); + }catch(\Excenption $e){ + return $this->Error('更新失敗'); + } + + return $this->Success($result); + } + + public function uploadAvatar(){ + + $files = request()->file('file'); + $savename = \think\facade\Filesystem::disk('public')->putFile( input('user_id'), $files); + + $avatar = getUrl().'/storage/'.$savename; + + + // Db::name('user') + // ->where('user_id',input('user_id')) + // ->update(['avatar'=>$avatar]); + + return $this->Success($avatar); + } + + public function updateSendCount(){ + $user_id = input('userid'); + + Db::name('user') + ->where('user_id',input('userid')) + ->exp('send_count', 'send_count+1') + ->update(); + // ->inc('send_count',1); + + return $this->Success('更新成功'); + } + +} diff --git a/app/appapi/middleware.php b/app/appapi/middleware.php new file mode 100644 index 0000000..73ebeea --- /dev/null +++ b/app/appapi/middleware.php @@ -0,0 +1,6 @@ +auth->auth(); + } catch (TokenExpiredException $e) { // token過期 + // 嘗試刷新token,會將舊token加入黑名單 + try { + $this->auth->setRefresh(); + $token = $this->auth->refresh(); + $payload = $this->auth->auth(false); + } catch (TokenBlacklistGracePeriodException $e) { + $payload = $this->auth->auth(false); + } catch (JWTException $exception) { + // 如果捕獲到此異常,即代表 refresh 也過期了,用户無法刷新令牌,需要重新登錄。 + throw new HttpException(401, $exception->getMessage()); + } + } catch (TokenBlacklistGracePeriodException $e) { // 捕獲黑名單寬限期 + $payload = $this->auth->auth(false); + } catch (TokenBlacklistException $e) { // 捕獲黑名單,退出登錄或者已經自動刷新,當前token就會被拉黑 + throw new HttpException(401, 'not login...'); + } + + $request->uid = $payload['user_id']->getValue(); + + $response = $next($request); + + if (isset($token)) { + $this->setAuthentication($response, $token); + } + + return $response; + } +} \ No newline at end of file diff --git a/app/appapi/route/app.php b/app/appapi/route/app.php new file mode 100644 index 0000000..21ec424 --- /dev/null +++ b/app/appapi/route/app.php @@ -0,0 +1,10 @@ +middleware(\app\api\middleware\JWT::class); + +Route::rule(':version/:controller/:action','appapi/:version.:controller/:action'); diff --git a/app/common/lib/JWT.php b/app/common/lib/JWT.php new file mode 100644 index 0000000..ba35d6b --- /dev/null +++ b/app/common/lib/JWT.php @@ -0,0 +1,15 @@ +