get('https://api.weixin.qq.com/cgi-bin/token', [ 'grant_type' => 'client_credential', 'appid' => $appId, 'secret' => $secret, ]); $payload = $response->json(); if (! is_array($payload) || ! empty($payload['errcode'])) { throw new RuntimeException((string) ($payload['errmsg'] ?? '获取微信 access_token 失败')); } $token = $payload['access_token'] ?? null; if (! is_string($token) || $token === '') { throw new RuntimeException('微信 access_token 响应异常'); } return $token; }); } public function getUnlimitedWxaCode(string $page, string $scene): string { $scene = trim($scene); if ($scene === '') { throw new RuntimeException('签到码不能为空'); } if (strlen($scene) > 32) { throw new RuntimeException('签到码不能超过 32 个字符'); } $token = $this->getAccessToken(); $response = Http::timeout(20) ->withHeaders(['Content-Type' => 'application/json']) ->post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={$token}", [ 'scene' => $scene, 'page' => ltrim($page, '/'), 'check_path' => false, 'env_version' => config('services.wechat.mini_program.env_version', 'develop'), 'width' => 430, ]); $contentType = (string) $response->header('Content-Type'); if (str_contains($contentType, 'json') || str_starts_with(trim($response->body()), '{')) { $payload = $response->json(); if (is_array($payload) && ! empty($payload['errcode'])) { throw new RuntimeException((string) ($payload['errmsg'] ?? '生成小程序码失败')); } } $body = $response->body(); if ($body === '') { throw new RuntimeException('生成小程序码失败:空响应'); } return $body; } /** * @return array{openid: string, unionid?: string, session_key: string} */ public function codeToSession(string $code): array { $appId = config('services.wechat.mini_program.app_id'); $secret = config('services.wechat.mini_program.secret'); if (! $appId || ! $secret) { throw new RuntimeException('微信小程序 AppID/Secret 未配置'); } $response = Http::timeout(10)->get('https://api.weixin.qq.com/sns/jscode2session', [ 'appid' => $appId, 'secret' => $secret, 'js_code' => $code, 'grant_type' => 'authorization_code', ]); $payload = $response->json(); if (! is_array($payload)) { throw new RuntimeException('微信登录响应异常'); } if (! empty($payload['errcode'])) { throw new RuntimeException((string) ($payload['errmsg'] ?? '微信登录失败')); } if (empty($payload['openid'])) { throw new RuntimeException('微信登录未返回 openid'); } return [ 'openid' => (string) $payload['openid'], 'unionid' => isset($payload['unionid']) ? (string) $payload['unionid'] : null, 'session_key' => (string) ($payload['session_key'] ?? ''), ]; } }