$expireAt, 'sign' => self::signDepositLink($orderNo, $expireAt), ]; } public static function signDepositLink(string $orderNo, int $expireAt): string { $params = [ 'expire_at' => strval($expireAt), 'order_no' => $orderNo, 'secret' => self::linkSecret(), ]; ksort($params); $pairs = []; foreach ($params as $key => $value) { $pairs[] = $key . '=' . $value; } return strtoupper(md5(implode('&', $pairs))); } public static function verifyDepositLink(string $orderNo, int $expireAt, string $sign): bool { $signNorm = strtoupper(trim($sign)); if ($signNorm === '' || $orderNo === '' || $expireAt <= 0) { return false; } return hash_equals(self::signDepositLink($orderNo, $expireAt), $signNorm); } /** * 前端静态收银台 URL(优先于服务端内联页) * * @param string $amountDisplay 2 位小数字符串,供页面展示 * @param string $bonusDisplay 2 位小数字符串 */ public static function depositPageUrl( string $orderNo, string $publicOrigin, int $expireAt, string $sign, string $amountDisplay = '', string $bonusDisplay = '' ): string { $htmlBase = self::resolveHtmlBase($publicOrigin); $apiBase = rtrim($publicOrigin, '/'); $query = [ 'order_no' => $orderNo, 'expire_at' => strval($expireAt), 'sign' => $sign, 'api_base' => $apiBase, ]; if ($amountDisplay !== '') { $query['amount'] = $amountDisplay; } if ($bonusDisplay !== '') { $query['bonus'] = $bonusDisplay; } $returnGameUrl = self::resolveGameReturnUrl(); if ($returnGameUrl !== '') { $query['return_game_url'] = $returnGameUrl; } return $htmlBase . '/mock-deposit.html?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986); } /** * 模拟页内确认支付接口(无需 auth-token;须携带 sign + expire_at) */ public static function depositConfirmUrl(string $orderNo, string $publicOrigin, int $expireAt, string $sign): string { $base = rtrim($publicOrigin, '/'); $query = http_build_query([ 'order_no' => $orderNo, 'expire_at' => strval($expireAt), 'sign' => $sign, ], '', '&', PHP_QUERY_RFC3986); return $base . '/api/finance/mockDepositConfirm?' . $query; } /** * 解析前端静态页根地址:MOCK_DEPOSIT_HTML_BASE > DDPAY_PUBLIC_BASE_URL > API 公网根 */ public static function resolveHtmlBase(string $publicOrigin): string { $raw = getenv('MOCK_DEPOSIT_HTML_BASE'); if (is_string($raw) && trim($raw) !== '') { return rtrim(trim($raw), '/'); } $ddpayPublic = getenv('DDPAY_PUBLIC_BASE_URL'); if (is_string($ddpayPublic) && trim($ddpayPublic) !== '') { return rtrim(trim($ddpayPublic), '/'); } $cfg = config('app.ddpay_public_base_url', ''); if (is_string($cfg) && trim($cfg) !== '') { return rtrim(trim($cfg), '/'); } return rtrim($publicOrigin, '/'); } /** * 模拟充值完成后「返回游戏」跳转地址(H5_GAME_URL) */ public static function resolveGameReturnUrl(): string { $raw = getenv('H5_GAME_URL'); if (is_string($raw) && trim($raw) !== '') { return trim($raw); } $cfg = config('app.h5_game_url', ''); if (is_string($cfg) && trim($cfg) !== '') { return trim($cfg); } return ''; } private static function linkSecret(): string { $raw = getenv('FINANCE_MOCK_PAY_LINK_SECRET'); if (is_string($raw) && trim($raw) !== '') { return trim($raw); } $auth = getenv('AUTH_TOKEN_SECRET'); if (is_string($auth) && trim($auth) !== '') { return trim($auth); } return 'mock-deposit-link-dev-secret'; } }