webhook = $config['webhook'] ?? null; $this->secret = $config['secret'] ?? null; } public function sendText(string $message, array $atMobiles = [], bool $atAll = false): void { if (empty($this->webhook)) { Log::warning('DingTalk webhook is not configured, skip sending alert. Alert content logged below.', [ 'message' => $message, 'atMobiles' => $atMobiles, 'atAll' => $atAll, ]); return; } $payload = [ 'msgtype' => 'text', 'text' => [ 'content' => $message, ], 'at' => [ 'atMobiles' => $atMobiles, 'isAtAll' => $atAll, ], ]; $url = $this->webhook; if (!empty($this->secret)) { $timestamp = (int) round(microtime(true) * 1000); $stringToSign = $timestamp . "\n" . $this->secret; $sign = base64_encode(hash_hmac('sha256', $stringToSign, $this->secret, true)); $encodedSign = urlencode($sign); $separator = str_contains($url, '?') ? '&' : '?'; $url .= "{$separator}timestamp={$timestamp}&sign={$encodedSign}"; } try { Http::timeout(10)->asJson()->post($url, $payload); } catch (\Throwable $e) { Log::error('Failed to send DingTalk alert', [ 'message' => $e->getMessage(), ]); } } }