input('tk', '')); $module = trim(strtolower($request->input('module', ''))); $pk = substr($request->input('pk', ''), 0, 16); $inputSign = $request->input('sn', ''); $timestamp = intval($request->input('tm', 0)); $rateType = substr($request->input('rate_type', ''), 0, 32); // 指定的比特率. $authService = new AuthService(); if (empty($zuhe)) { return self::responseM3u8Raw('参数错误1', true); } if (!in_array($module, ['video', 'ad', 'goods', 'shop'])) { // 判断模块合法性. return self::responseM3u8Raw('参数错误2', true); } $nowDateObj = Carbon::now(); $startCheckDate = '2022-08-01 04:45:33'; $startCheckObj = Carbon::parse($startCheckDate); if ($nowDateObj > $startCheckObj && in_array($module, ['video'])) { // 大于这个日期, 且视频模块, 才检查签名参数. if (!empty($timestamp) && strlen($timestamp) == 10) { $inputDateObj = Carbon::createFromTimestamp($timestamp); if (abs($inputDateObj->diffInHours($nowDateObj)) >= 3) { return self::responseM3u8Raw('参数错误6', true); } } else { return self::responseM3u8Raw('参数错误7', true); } } $zuhe2 = caesar_decode($zuhe, 'l,n', 3); // 偏移了3 $previewFlag = substr($zuhe2, 0, 2); $queryDeviceType = substr($zuhe2, 2, 1); $queryDeviceNo = substr($zuhe2, 7, strlen($zuhe2) - 7); $sign = M3u8CacheRepository::generateSign($zuhe2, $timestamp); if ($sign !== $inputSign) { return self::responseM3u8Raw('参数错误8', true); } $cacheKey = $authService->getUserDeviceCacheKey($queryDeviceNo, $queryDeviceType); $cache = make(CacheInterface::class); $cacheToken = $cache->has($cacheKey) ? $cache->get($cacheKey) : ''; if (empty($cacheToken)) { return self::responseM3u8Raw('参数错误4', true); } $jwtRepo = make(JwtRepository::class); $aud = 'app-users'; $validateResult = $jwtRepo->validateToken($cacheToken, $aud); if (!$validateResult['is_valid']) { if ($validateResult['is_expired']) { return self::responseM3u8Raw('参数错误2', true); } return self::responseM3u8Raw('参数错误3', true); } // 破解版专门一个m3u8 $tokenObj = $validateResult['token_obj']; $hUserCode = $tokenObj->claims()->get('user_id'); // $hDeviceNo = $tokenObj->claims()->get('device_no'); $hDeviceType = $tokenObj->claims()->get('device_type'); // $hFingerHash = $tokenObj->claims()->get('finger_hash'); $hIp = $tokenObj->claims()->get('ip'); $hVersion = $tokenObj->claims()->get('version'); if ($hDeviceType == 'A') { if (version_compare($hVersion, '1.1.1', '<') || version_compare($hVersion, '1.99.1', '>')) { $crackedM3u8Url = 'v2|/20220831/pPlRwPcF/1000kb/hls/index.m3u8'; $m3u8Params1 = [ 'url' => $crackedM3u8Url, 'is_preview' => false, ]; $raw = M3u8CacheRepository::getMu38Raw($m3u8Params1, true); return self::responseM3u8Raw($raw); } } // M3u8验证IP. $clientIp = make(CommonService::class)->getIp(); if ($hIp !== $clientIp) { // make(UserRepository::class)->userLogout($hUserCode); logger('api-M3u8Controller-ip', ['token_ip' => $hIp, 'user_ip' => $clientIp]); // return self::responseM3u8Raw('参数错误9', true); } $cache = make(CacheInterface::class); $rateTypeKey = !empty($rateType) ? $rateType : 'empty'; $cacheKey = $module . ':raw:'. $pk . ':'. $rateTypeKey; $cacheSeconds = 7 * 24 * 60 * 60; $arrItem = $cache->get($cacheKey, []); $m3u8PlayUrl = ''; $previewTime = VideoConstant::PREVIEW_TIME; $playerType = 1; if (empty($arrItem)) { switch ($module) { case 'video': $item = $videoRepository->findBy('id', $pk, ['id', 'mu']); if (!empty($item->mu)) { $m3u8PlayUrl = $item->mu; } break; case 'ad': $item = $adRepository->findBy('id', $pk, ['id', 'play']); if (!empty($item->play)) { $m3u8PlayUrl = $item->play; } break; case 'shop': $item = $shopsRepository->findBy('uid', $pk, ['video_address']); if (!empty($item->video_address)) { $m3u8PlayUrl = $item->video_address; } break; case 'goods': $item = $goodsRepository->findBy('uid', $pk, ['video_address']); if (!empty($item->video_address)) { $m3u8PlayUrl = $item->video_address; } break; } if (empty($item)) { return self::responseM3u8Raw('参数错误5', true); } $arrItem = $item->toArray(); $arrItem['m3u8_play_url'] = $m3u8PlayUrl; $cache->set($cacheKey, $arrItem, $cacheSeconds); } $isPreview = true; // 默认预览 if ($previewFlag == 'k4') { // 标识 k4=完整,t5=预览 $isPreview = false; } $m3u8FieldUrl = $arrItem['m3u8_play_url']; $itemInfo = [ 'url' => $m3u8FieldUrl, 'is_preview' => $isPreview, // 'preview_time' => $previewTime, ]; $raw = M3u8CacheRepository::getMu38Raw($itemInfo, true); return self::responseM3u8Raw($raw); } /** * @return string[] */ private function getHeaders() { return [ 'Content-Type' => 'application/x-mpegURL', ]; } /** * 返回raw * @param $raw * @param bool $isError * @return \Psr\Http\Message\ResponseInterface */ private function responseM3u8Raw($raw, $isError = false) { if (config('app_debug') && $isError == true && config('app_env') != 'prod') { return json_fail($raw); } else { if ($isError == true) { return response('', 200, self::getHeaders()); } else { return response($raw, 200, self::getHeaders()); } } } }