loginUrl('wechat', 'https://www.example.com/login/callback', $state); * header('Location: ' . $url); * // 2. 回调地址中 * $user = $client->user($_GET['code']); */ class SiyunLogin { /** @var string */ private $appId; /** @var string */ private $appSecret; /** @var string */ private $baseUrl; public function __construct(string $appId, string $appSecret, string $baseUrl = 'https://login.siyun223.com') { $this->appId = $appId; $this->appSecret = $appSecret; $this->baseUrl = rtrim($baseUrl, '/'); } /** * 获取登录地址 * * @param string $type wechat、qq、alipay、douyin */ public function loginUrl(string $type, string $redirectUri, string $state = ''): string { $data = $this->request('/api/v1/login/url', [ 'type' => $type, 'redirect_uri' => $redirectUri, 'state' => $state, ]); return (string) $data['url']; } /** * 用回调地址中的 code 换取用户信息 * * @return array{openid: string, type: string, type_name: string, method: string, method_name: string, nickname: string, avatar: string} */ public function user(string $code): array { return $this->request('/api/v1/login/user', ['code' => $code]); } public function sign(array $params): string { unset($params['sign']); ksort($params, SORT_STRING); $pairs = []; foreach ($params as $key => $value) { if ($value === null || $value === '' || is_array($value)) { continue; } $pairs[] = $key . '=' . $value; } return hash_hmac('sha256', implode('&', $pairs), $this->appSecret); } private function request(string $path, array $params): array { $params['app_id'] = $this->appId; $params['timestamp'] = (string) time(); $params['nonce'] = bin2hex(random_bytes(16)); $params['sign'] = $this->sign($params); $ch = curl_init($this->baseUrl . $path); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($params), CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_HTTPHEADER => ['Accept: application/json'], ]); $body = curl_exec($ch); $error = curl_error($ch); if (PHP_VERSION_ID < 80000) { curl_close($ch); } if ($body === false) { throw new RuntimeException('请求聚合登录接口失败:' . $error); } $result = json_decode((string) $body, true); if (! is_array($result)) { throw new RuntimeException('聚合登录接口返回格式异常'); } if ((int) ($result['code'] ?? -1) !== 0) { throw new RuntimeException((string) ($result['msg'] ?? '聚合登录接口返回错误'), (int) ($result['code'] ?? 0)); } return (array) $result['data']; } }