resolveTimestamp(); if ($timestamp === null) { return self::FAILURE; } $baseUrl = $this->resolveBaseUrl(); $query = SignupChannel::query()->with('competition'); $this->applyCompetitionFilter($query); $this->applyChannelFilter($query); if (! $this->option('include-disabled')) { $query->where('status', SignupChannel::STATUS_ENABLED); } if ($this->option('require-encryption')) { $query->where('entry_encryption_enabled', true); } try { $channels = $query ->orderBy('competition_id') ->orderBy('id') ->get(); } catch (Throwable $exception) { $this->error('读取渠道数据失败:'.$exception->getMessage()); return self::FAILURE; } if ($channels->isEmpty()) { $this->warn('未找到符合条件的渠道。'); return self::FAILURE; } $rows = []; foreach ($channels as $channel) { $competition = $channel->competition; $publicKey = (string) $channel->encryption_public_key; $parameters = [ 'channel_code' => (string) $channel->channel_code, 'timestamp' => (string) $timestamp, 'name' => $this->protectedValue($this->stringOption('name'), $channel, $publicKey), 'mobile' => $this->protectedValue($this->stringOption('mobile'), $channel, $publicKey), 'company_name' => $this->protectedValue($this->stringOption('company-name'), $channel, $publicKey), 'state' => $this->stringOption('state'), ]; $parameters['hash'] = ChannelEntrySignature::make($parameters, $channel->shared_secret); $url = $baseUrl.'/channel-entry?'.http_build_query($parameters, '', '&', PHP_QUERY_RFC3986); if ($this->option('plain')) { $this->line($url); continue; } $rows[] = [ 'competition' => $competition ? "{$competition->id}:{$competition->slug}" : '(missing)', 'channel' => "{$channel->id}:{$channel->channel_name}", 'status' => $channel->status, 'encryption' => $channel->entry_encryption_enabled ? 'enabled' : 'disabled', 'channel_code' => $channel->channel_code, 'url' => $url, ]; } if (! $this->option('plain')) { $this->table(['赛事', '渠道', '状态', '入口加密', '渠道编码', '测试入口 URL'], $rows); } return self::SUCCESS; } private function resolveTimestamp(): ?int { $raw = $this->option('timestamp'); if ($raw === null || trim((string) $raw) === '') { return time(); } $timestamp = trim((string) $raw); if (! ctype_digit($timestamp)) { $this->error('--timestamp 必须是秒级 Unix 时间戳。'); return null; } return (int) $timestamp; } private function resolveBaseUrl(): string { $raw = trim((string) ($this->option('base-url') ?: config('app.url', 'http://localhost'))); $raw = $raw !== '' ? $raw : 'http://localhost'; return rtrim($raw, '/'); } /** * @param Builder $query */ private function applyCompetitionFilter(Builder $query): void { $competition = trim((string) $this->option('competition')); if ($competition === '') { return; } $query->whereHas('competition', function (Builder $builder) use ($competition): void { if (ctype_digit($competition)) { $builder->where('id', (int) $competition); } else { $builder->where('slug', $competition); } }); } /** * @param Builder $query */ private function applyChannelFilter(Builder $query): void { $channel = trim((string) $this->option('channel')); if ($channel === '') { return; } if (ctype_digit($channel)) { $query->where('id', (int) $channel); } else { $query->where('channel_code', $channel); } } private function stringOption(string $name): string { $value = $this->option($name); return is_scalar($value) ? trim((string) $value) : ''; } private function protectedValue(string $value, SignupChannel $channel, string $publicKey): string { return $value === '' || ! $channel->entry_encryption_enabled ? $value : ChannelEntryEncryption::encrypt($value, $publicKey); } }