dd/app/Services/Cron/ReportUmami.php
2026-08-13 15:19:00 +08:00

150 lines
4.7 KiB
PHP
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace App\Services\Cron;
use App\Services\TomTool\Telegram\Slave as TeleSlave;
/**
* 定时获取 Umami 统计信息并发送至 Telegram 机器人
*/
final class ReportUmami
{
private string $baseUrl;
private string $username = 'admin';
private string $password = 'taonihouzi#';
public function __construct()
{
$this->baseUrl = (string) config('path.url_umami_base');
}
/**
* 定时任务入口方法
*/
public function handle(): void
{
try {
// 1. 获取 API 认证 Token
$token = $this->getAuthToken();
if (!$token) {
TeleSlave::log()->send("⚠️ [Umami 报表失败]: 无法获取 Auth Token请检查账号密码。");
return;
}
// 2. 获取网站列表
$websites = $this->getWebsites($token);
if (empty($websites)) {
TeleSlave::log()->send(" [Umami 报表]: 数据库中未找到任何网站。");
return;
}
// 3. 统计过去 24 小时的数据
$endAt = microtime(true) * 1000; // 当前时间戳 (毫秒)
$startAt = $endAt - (24 * 3600 * 1000); // 24小时前的时间戳 (毫秒)
$msg = "<b>📊 Umami 每日站点数据日报</b>\n";
$msg .= "----------------------------\n";
foreach ($websites as $site) {
$siteId = $site['id'];
$siteName = $site['name'];
$domain = $site['domain'] ?? '';
// 获取单个网站的统计指标
$stats = $this->getWebsiteStats($token, $siteId, (int)$startAt, (int)$endAt);
if ($stats) {
$pageviews = $stats['pageviews']['value'] ?? 0;
$visitors = $stats['visitors']['value'] ?? 0;
$visits = $stats['visits']['value'] ?? 0;
$bounces = $stats['bounces']['value'] ?? 0;
// 计算跳出率
$bounceRate = $visits > 0 ? round(($bounces / $visits) * 100, 1) : 0;
$msg .= "🌐 <b>{$siteName}</b> ({$domain})\n";
$msg .= "├ 👁️ 页面浏览 (PV): <b>{$pageviews}</b>\n";
$msg .= "├ 👤 独立访客 (UV): <b>{$visitors}</b>\n";
$msg .= "├ 🔄 会话次数: <b>{$visits}</b>\n";
$msg .= "└ 📉 跳出率: <b>{$bounceRate}%</b>\n\n";
}
}
// 4. 发送日志至 Telegram
TeleSlave::log()->send($msg);
} catch (\Throwable $e) {
TeleSlave::log()->send("❌ [Umami 报表异常]: " . $e->getMessage());
}
}
/**
* 1. 登录 Umami 获取 JWT Token
*/
private function getAuthToken(): ?string
{
$response = $this->curlRequest('POST', '/api/auth/login', [
'username' => $this->username,
'password' => $this->password,
]);
return $response['token'] ?? null;
}
/**
* 2. 获取网站列表
*/
private function getWebsites(string $token): array
{
$response = $this->curlRequest('GET', '/api/websites', [], $token);
return $response['data'] ?? $response ?? [];
}
/**
* 3. 获取指定网站的统计数据
*/
private function getWebsiteStats(string $token, string $siteId, int $startAt, int $endAt): ?array
{
$endpoint = sprintf('/api/websites/%s/stats?startAt=%d&endAt=%d', $siteId, $startAt, $endAt);
return $this->curlRequest('GET', $endpoint, [], $token);
}
/**
* 通用 cURL 请求工具方法
*/
private function curlRequest(string $method, string $path, array $data = [], ?string $token = null): ?array
{ organize:
$ch = curl_init($this->baseUrl . $path);
$headers = [
'Content-Type: application/json',
'Accept: application/json',
];
if ($token) {
$headers[] = 'Authorization: Bearer ' . $token;
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 200 && $httpCode < 300 && $result) {
return json_decode($result, true);
}
return null;
}
}