__handlePropertyHandler(__CLASS__); } /** * 签名token/key * @var string */ private $signToken = 'uwgnnDtzTZR1xzoW'; /** * @var null|AuthService */ private $authService = null; /** * @var null|UserRepository */ private $userRepo = null; /** * @var null|CacheInterface */ private $cacheRepo = null; public function index() { return 'pc-ok-pong'; } /** * 轮询登陆是否成功. * @return mixed * @throws \Psr\SimpleCache\InvalidArgumentException */ public function lookup() { $qrcodeContent = trim(request()->input('qc', '')); $qrFrom = request()->input('from', 'web'); $qrInfo = $this->getUserCodeByQrCode($qrcodeContent); if (!empty($qrInfo['err_msg'])) { return $this->jsonFail($qrInfo['err_msg'], 5001); } $realUserCode = ''; $userCode = $qrInfo['user_code']; $userInfo = $this->getAuthInfo(); if (!empty($userInfo['code'])) { return $this->jsonFail('授权无效1', 5002); } if ($userInfo['code'] !== $userCode) { return $this->jsonFail('授权非法1', 5003); } $status = 2; // 状态,1=拿到token,2=未拿到,未登陆状态 $cacheKey = $this->getAuthService()->getUserCacheKey($userCode); $token = $this->getCacheRepo()->get($cacheKey, ''); if (empty($token)) { $status = 1; } else { $realUserCode = $userCode; } $result = ['status' => $status, 'token' => $token, 'user_code' => $realUserCode]; return $this->jsonSuccess($result); } /** * 检查是否合法登陆 * @return mixed */ public function checkLogin() { $userInfo = $this->getAuthInfo(); if (empty($userInfo['code'])) { return $this->jsonFail('授权无效', 5091); } $result = ['is_success' => true]; return $this->jsonSuccess($result); } public function setting() { $userInfo = $this->getAuthInfo(); if (empty($userInfo['code'])) { return $this->jsonFail('授权无效', 5091); } $userCode = $userInfo['code']; $configRepo = make(ConfigRepoistory::class); $creatorRepo = make(CreatorRepository::class); $ruleRepo = make(CreatorRuleRepository::class); $detail = $creatorRepo->detail($userCode); $todayCanUpload = false; $level = 0; $dayAddonNum = 0; $dayVideo = 0; if (!empty($detail)) { $level = intval($detail->level); $dayAddonNum = intval($detail->day_addon_num); $dayVideo = intval($detail->day_video); } $ruleLevel = $ruleRepo->getRuleByLevel($level); $dayMaxVideo = intval($ruleLevel->day_max_video) + $dayAddonNum; $todayVideo = !empty($detail) ? $dayVideo : 0; if ($todayVideo < $dayMaxVideo) { $todayCanUpload = true; } $fileMaxSizeMb = CreatorConstant::VIDEO_MAX_SIZE_MB; // 文件最大多少MB $maxCoin = CreatorConstant::VIDEO_SELL_MAX_COIN; // 最多设置金币个数 $creatorMinVideoNum = CreatorConstant::FREE_VIDEO_NUM; // 创作者,level>0 $normalMinVideoNum = CreatorConstant::LEVEL_0_FREE_VIDEO_NUM; // 普通人, level=0 $maxTagNum = CreatorConstant::VIDEO_TAG_MAX_NUM; // 最多选择标签个数. $tags = $creatorRepo->canUseTags(); $ppvodParams = $configRepo->gets(['ppvod_upload_category', 'ppvod_upload_tpl_id', 'ppvod_upload_tpl_name'], 'sys', []); $isCanUploadCoin = isset($detail->coin_uper) ? boolval($detail->coin_uper) : false; // 是否能传收费视频 $needUploadFreeNum = 0; // 还需要上传免费视频个数. $countFreeVideos = $creatorRepo->countPublishedCoinVideo($userCode, true); // 统计免费视频个数 $countNotFreeVideos = $creatorRepo->countPublishedCoinVideo($userCode, false); //统计收费视频个数 if ($level <= 0) { if (CreatorConstant::LEVEL_0_FREE_VIDEO_NUM > 0) { // 金币视频 x 免费要求 = 最低历史上传免费个数 $leastFreeNum = $countNotFreeVideos > 0 ? $countNotFreeVideos * CreatorConstant::LEVEL_0_FREE_VIDEO_NUM : CreatorConstant::LEVEL_0_FREE_VIDEO_NUM; if ($countFreeVideos >= $leastFreeNum) { $isCanUploadCoin = true; } else { $needUploadFreeNum = $leastFreeNum - $countFreeVideos; } } else { $isCanUploadCoin = true; } } else { if (CreatorConstant::FREE_VIDEO_NUM > 0) { // 金币视频 x 免费要求 = 最低限制上传免费个数 $leastFreeNum = $countNotFreeVideos > 0 ? $countNotFreeVideos * CreatorConstant::FREE_VIDEO_NUM : CreatorConstant::FREE_VIDEO_NUM; if ($countFreeVideos >= $leastFreeNum) { $isCanUploadCoin = true; } else { $needUploadFreeNum = $leastFreeNum - $countFreeVideos; } } else { $isCanUploadCoin = true; } } $uploadIsMaintenance = false; $uploadMaintenanceDesc = ''; $arrConfig = $configRepo->gets(['upload_maintenance_status', 'upload_maintenance_desc'], 'sys', []); if (isset($arrConfig['upload_maintenance_status']) && intval($arrConfig['upload_maintenance_status']) == 1) { $uploadIsMaintenance = true; $uploadMaintenanceDesc = $arrConfig['upload_maintenance_desc'] ?? '上传维护中,请稍后恢复再试'; } $result = ['user_id' => $userInfo['code'], 'nick' => $userInfo['nick'], 'level' => $level, 'today_can_upload' => $todayCanUpload, 'file_max_size_mb' => $fileMaxSizeMb, 'max_coin' => $maxCoin, 'creator_min_video_num' => $creatorMinVideoNum, 'normal_min_video_num' => $normalMinVideoNum, 'max_tag_num' => $maxTagNum, 'tags' => $tags, 'is_can_upload_coin' => $isCanUploadCoin, 'need_upload_free_num' => $needUploadFreeNum, 'count_free_videos' => $countFreeVideos, 'count_not_free_videos' => $countNotFreeVideos, 'upload_category' => !empty($ppvodParams['ppvod_upload_category']) ? $ppvodParams['ppvod_upload_category'] : '用户上传', 'upload_tpl_id' => !empty($ppvodParams['ppvod_upload_tpl_id']) ? $ppvodParams['ppvod_upload_tpl_id'] : '', 'upload_tpl_name' => !empty($ppvodParams['ppvod_upload_tpl_name']) ? $ppvodParams['ppvod_upload_tpl_name'] : '默认', 'upload_is_maintenance' => $uploadIsMaintenance, 'upload_maintenance_desc' => $uploadMaintenanceDesc]; return $this->jsonSuccess($result); } public function createVideo() { $userInfo = $this->getAuthInfo(); if (empty($userInfo['code'])) { return $this->jsonFail('授权无效', 5091); } $userCode = $userInfo['code']; $validatorFactory = make(ValidatorFactoryInterface::class); $inputData = request()->all(); $rules = [ 'title' => 'required', 'cover' => 'nullable|max:700', 'coins' => 'required|int', 'tags' => 'required', // 这个是ID 'file_hash' => 'required', ]; $validator = $validatorFactory->make($inputData, $rules); if ($validator->fails()) { // 如果有错误(可能是多个信息),这里只取第一个错误信息返回. return json_fail($validator->errors()->first()); } $videoRepo = make(VideoRepository::class); if ($videoRepo->checkExist($inputData['file_hash'])) { return $this->jsonFail('此视频已被其他人上传过,请重新更换', 6444); } $mediaCenterRepo = make(MediaCenterRepository::class); $hashVideoInfo = $mediaCenterRepo->getHashInfo($inputData['file_hash']); if (!empty($hashVideoInfo)) { return $this->jsonFail('此视频有人上传过了,请重新更换', 6444); } $ruleRepo = make(CreatorRuleRepository::class); $creatorRepo = make(CreatorRepository::class); $detail = $creatorRepo->detail($userCode); $level = 0; $dayAddonNum = 0; $dayVideo = 0; if (!empty($detail)) { $level = intval($detail->level); $dayAddonNum = intval($detail->day_addon_num); $dayVideo = intval($detail->day_video); } else { // 自动申请为原创者. $detail = $creatorRepo->applyToUncheck($userCode); $level = intval($detail->level); } $ruleLevel = $ruleRepo->getRuleByLevel($level); $dayMaxVideo = intval($ruleLevel->day_max_video) + $dayAddonNum; $todayVideo = !empty($detail) ? $dayVideo : 0; if ($todayVideo >= $dayMaxVideo) { return $this->jsonFail('今日已经超出上传数量限制'); } $cover = trim(data_get($inputData, 'cover', '')); $cover = substr($cover, 0, 255); $coins = intval(data_get($inputData, 'coins', 0)); // 金币,单位数量个,10金币=1元人民币 $uploadingUrl = ''; // TODO,这里可以做一个固定视频,等待用户上传转码中. if ($coins < 0) { $coins = 0; } if ($coins > CreatorConstant::VIDEO_SELL_MAX_COIN) { return $this->jsonFail('售卖金币价格太大,可以提前联系客服'); } $arrTagIds = []; $tmpTagIds = data_get($inputData, 'tags', ''); if (is_string($tmpTagIds)) { $arrTagIds = explode(',', $tmpTagIds); } else { $arrTagIds = $tmpTagIds; } if (!empty($arrTagIds)) { $arrTagIds = array_filter($arrTagIds); $arrTagIds = array_unique($arrTagIds); } if (empty($arrTagIds)) { return $this->jsonFail('请选择至少1个口味'); } if (count($arrTagIds) > CreatorConstant::VIDEO_TAG_MAX_NUM) { return $this->jsonFail('最多选择' . strval(CreatorConstant::VIDEO_TAG_MAX_NUM) . '个口味'); } // 处理关联标签. $tagIdsRaltion = []; $tagNames = []; if (!empty($arrTagIds)) { foreach ($arrTagIds as $v) { $tagObj = TypeModel::query()->where('id', $v)->first(); if (!empty($tagObj->id)) { $tagIdsRaltion[] = $tagObj->id; $tagNames[] = $tagObj->title; } } } $isCanUploadCoin = isset($detail->coin_uper) ? boolval($detail->coin_uper) : false; // 是否能传收费视频 $needUploadFreeNum = 0; // 还需要上传免费视频个数. $countFreeVideos = $creatorRepo->countPublishedCoinVideo($userCode, true); // 统计免费视频个数 $countNotFreeVideos = $creatorRepo->countPublishedCoinVideo($userCode, false); //统计收费视频个数 if ($level <= 0) { if (CreatorConstant::LEVEL_0_FREE_VIDEO_NUM > 0) { // 金币视频 x 免费要求 = 最低历史上传免费个数 $leastFreeNum = $countNotFreeVideos > 0 ? $countNotFreeVideos * CreatorConstant::LEVEL_0_FREE_VIDEO_NUM : CreatorConstant::LEVEL_0_FREE_VIDEO_NUM; if ($countFreeVideos >= $leastFreeNum) { $isCanUploadCoin = true; } else { $needUploadFreeNum = $leastFreeNum - $countFreeVideos; } } else { $isCanUploadCoin = true; } } else { if (CreatorConstant::FREE_VIDEO_NUM > 0) { // 金币视频 x 免费要求 = 最低限制上传免费个数 $leastFreeNum = $countNotFreeVideos > 0 ? $countNotFreeVideos * CreatorConstant::FREE_VIDEO_NUM : CreatorConstant::FREE_VIDEO_NUM; if ($countFreeVideos >= $leastFreeNum) { $isCanUploadCoin = true; } else { $needUploadFreeNum = $leastFreeNum - $countFreeVideos; } } else { $isCanUploadCoin = true; } } if ($coins > 0 && !$isCanUploadCoin) { return $this->jsonFail('还不能上传收费视频,请先再传' . strval($needUploadFreeNum) . '个免费视频'); } $payType = 2; // 默认金币 if ($coins == 0) { $payType = 1; // vip } $newStrTagNames = !empty($tagNames) ? implode(',', $tagNames) : ''; $newStrTagIds = !empty($arrTagIds) ? implode(',', $arrTagIds) : ''; $title = trim(data_get($inputData, 'title', '')); $title = mb_substr($title, 0, 24); $fileHash = trim(data_get($inputData, 'file_hash', '')); $fileHash = substr($fileHash, 0, 32); $setarr = ['uid' => $userCode, 'status' => 3, 'check' => 0, 'pay_type' => $payType, 'type' => 1, 'mu' => $uploadingUrl, 'title' => $title, 'cover' => $cover, 'coins' => $coins, 'tags' => $newStrTagNames, 'file_hash' => $fileHash, 'custom_cover' => $cover]; $videoObj = VideoModel::query()->create($setarr); if ($videoObj) { $videoId = $videoObj->id; if (!empty($tagIdsRaltion)) { foreach ($tagIdsRaltion as $tagId) { $setarr2 = ['type_id' => $tagId, 'video_id' => $videoId, 'status' => 1]; TypeVideoModel::query()->create($setarr2); } } // 累加今日上传视频数量. $detail->day_video++; $detail->save(); if (!empty($cover)) { $coverFileName = basename($cover); $coverExt = $this->fileExt($coverFileName); if ($coverExt != 'ceb' && in_array($coverExt, ['jpg', 'jpeg', 'png', 'gif'])) { $jobParams = ['video_id' => $videoId, 'cover' => $cover]; dispatch_job(new SavePcVideoCoverCebJob($jobParams)); } } } else { return $this->jsonFail('创建视频失败'); } $result = ['video' => ['id' => $videoObj->id]]; return $this->jsonSuccess($result); } /** * 二维码登陆 * @return mixed * @throws \Psr\SimpleCache\InvalidArgumentException */ public function qrcodeLogin() { $qrcodeContent = trim(request()->input('qc', '')); $qrFrom = request()->input('from', 'web'); $qrInfo = $this->getUserCodeByQrCode($qrcodeContent); if (!empty($qrInfo['err_msg'])) { return $this->jsonFail($qrInfo['err_msg']); } $userCode = $qrInfo['user_code']; // $cacheKey = $this->getAuthService()->getUserCacheKey($userCode); // $token = $this->getCacheRepo()->get($cacheKey); $tokenInfo = $this->getAuthService()->createSingleJwt($userCode); $token = $tokenInfo['token']; $result = ['token' => $token, 'user_code' => $userCode]; return $this->jsonSuccess($result); } public function upAuth() { $userInfo = $this->getAuthInfo(); if (empty($userInfo['code'])) { logger('upAuth', ['msg' => '[4]握手失败']); return response('[4]握手失败', 500); } $queryUserCode = $userInfo['code']; $inputData = request()->all(); $rules = ['auth_event' => 'required', 'auth_timestamp' => 'required', 'app_name' => 'required', 'auth_user' => 'required', 'auth_sign' => 'required|string', 'file_hash' => 'nullable', 'file_origin_name' => 'nullable', 'file_ext' => 'nullable']; $validator = make(ValidatorFactoryInterface::class)->make($inputData, $rules); if ($validator->fails()) { // 如果有错误(可能是多个信息),这里只取第一个错误信息返回. logger('upAuth', ['msg' => $validator->errors()->first()]); return response($validator->errors()->first(), 500); } $authTimestamp = strval(data_get($inputData, 'auth_timestamp', '')); $appName = data_get($inputData, 'app_name', ''); $authUserCode = data_get($inputData, 'auth_user', ''); $authSign = data_get($inputData, 'auth_sign', ''); $authEvent = data_get($inputData, 'auth_event', ''); $fileOriginName = data_get($inputData, 'file_origin_name', ''); $fileHash = data_get($inputData, 'file_hash', ''); $fileExt = strtolower(data_get($inputData, 'file_ext', '')); $tmpTimestamp = substr($authTimestamp, 0, 10); if (abs(Carbon::createFromTimestamp($tmpTimestamp)->diffInMinutes(Carbon::now())) > 30) { logger('upAuth', ['msg' => '[5]握手失败']); return response('[5]握手失败', 500); } $inSign = $this->createSign($authTimestamp, $appName, $authUserCode, $authEvent); if ($inSign !== $authSign) { logger('upAuth', ['msg' => '[3]握手失败']); return response('[3]握手失败', 500); } if (empty($queryUserCode) || $queryUserCode !== $authUserCode) { logger('upAuth', ['msg' => '[6]握手失败']); return response('[6]握手失败', 500); } return response('success', 200); } /** * 获取认证里的用户信息. * @return array */ private function getAuthInfo() { $authInfo = $this->getAuthService()->getTokenUserInfo(); if (empty($authInfo['user_id'])) { return []; } $userInfo = $this->getAuthService()->checkValid($authInfo['user_id']); if (empty($userInfo)) { return []; } $userInfo['user_id'] = $userInfo['code']; // 兼容. return $userInfo; } /** * 获取服务. * @return mixed|AuthService */ private function getAuthService() { if (!$this->authService instanceof AuthService) { $this->authService = make(AuthService::class); } return $this->authService; } /** * 获取用户仓库. * @return UserRepository|mixed */ private function getUserRepo() { if (!$this->userRepo instanceof UserRepository) { $this->userRepo = make(UserRepository::class); } return $this->userRepo; } /** * 获取缓存仓库. * @return mixed|CacheInterface */ private function getCacheRepo() { if (!$this->cacheRepo instanceof CacheInterface) { $this->cacheRepo = make(CacheInterface::class); } return $this->cacheRepo; } /** * 通过二维码内容获取用户code. * @param $qrcodeContent * @return string[] */ private function getUserCodeByQrCode($qrcodeContent) { $result = ['err_msg' => '', 'user_code' => '']; if (empty($qrcodeContent)) { $result['err_msg'] = '无效的二维码1'; return $result; } $txt = $qrcodeContent; if (empty($txt)) { $result['err_msg'] = '无效的二维码2'; return $result; } $account = hand_decrypt($txt, $this->getUserRepo()->getAcKey(), $this->getUserRepo()->getAcIv()); if (empty($account)) { $result['err_msg'] = '无效的二维码3'; return $result; } $pattern = '/^user:\\/\\/([a-zA-Z0-9]{6,12})/'; preg_match($pattern, $account, $matches); if (empty($matches[1])) { $result['err_msg'] = '无效的二维码4'; return $result; } $userCode = $matches[1]; $userInfo = $this->getUserRepo()->getUserInfoFromCache($userCode); if (empty($userInfo['code'])) { $result['err_msg'] = '无效的二维码5'; return $result; } $result['user_code'] = $userCode; return $result; } /** * @param $timestamp * @param $appName * @param $userCode * @return string */ private function createSign($timestamp, $appName, $userCode, $authEvent) { $strParams = $appName . '-' . $authEvent . '-' . $userCode . '-' . $timestamp; $strSign = md5(md5($strParams) . '-' . $this->signToken); return $strSign; } private function fileExt($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1))); } }