514 lines
20 KiB
PHP
514 lines
20 KiB
PHP
<?php
|
|
/**
|
|
* 📊 全面统计接口(整合版)
|
|
*
|
|
* @file stats_full.php
|
|
* @author AI Assistant
|
|
* @date 2026-04-10
|
|
* @version 2.0.0
|
|
* @desc 整合热门统计、在线统计、请求统计
|
|
* @lastUpdate 2026-04-10 整合api_hot/api_online/api_request_stats
|
|
*
|
|
* 访问地址: /api/stats_full.php
|
|
*
|
|
* 参数说明:
|
|
* - act: stats(全面统计) / hot(热门) / online(在线) / request(请求)
|
|
* - layer: basic(基础) / detail(详情) / full(完整) / hot(热门)
|
|
* - module: recipe / ingredient / category / tag / user / nutrition
|
|
* - period: today / month / total (热门统计时间范围)
|
|
*/
|
|
|
|
$startTime = microtime(true);
|
|
|
|
require '../zb_system/function/c_system_base.php';
|
|
$zbp->Load();
|
|
|
|
require_once 'cache.php';
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
|
|
|
$act = strtolower(trim($_GET['act'] ?? 'stats'));
|
|
$layer = strtolower(trim($_GET['layer'] ?? 'basic'));
|
|
$module = strtolower(trim($_GET['module'] ?? ''));
|
|
$period = strtolower(trim($_GET['period'] ?? 'total'));
|
|
|
|
$forceRefresh = isset($_GET['_refresh']) && $_GET['_refresh'] === '1';
|
|
|
|
$cacheKey = 'stats_' . $act . '_' . $layer . '_' . $module . '_' . $period;
|
|
$cachedResult = ApiCache::get('stats_full', array('act' => $act, 'layer' => $layer, 'module' => $module, 'period' => $period));
|
|
|
|
if ($cachedResult !== null && !$forceRefresh) {
|
|
$cachedResult['_cached'] = true;
|
|
$cachedResult['_query_time'] = round((microtime(true) - $startTime) * 1000, 2) . 'ms';
|
|
echo json_encode($cachedResult, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
exit;
|
|
}
|
|
|
|
$result = array('code' => 200, 'message' => 'success', 'data' => array());
|
|
|
|
switch ($act) {
|
|
case 'hot':
|
|
$result = get_hot_stats($period);
|
|
break;
|
|
case 'online':
|
|
$result = get_online_stats();
|
|
break;
|
|
case 'request':
|
|
$result = get_request_stats();
|
|
break;
|
|
case 'heartbeat':
|
|
$result = update_heartbeat();
|
|
break;
|
|
case 'stats':
|
|
default:
|
|
$result = get_full_stats($layer, $module);
|
|
break;
|
|
}
|
|
|
|
ApiCache::set('stats_full', array('act' => $act, 'layer' => $layer, 'module' => $module, 'period' => $period), $result);
|
|
|
|
$result['_cached'] = false;
|
|
$result['_query_time'] = round((microtime(true) - $startTime) * 1000, 2) . 'ms';
|
|
|
|
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
exit;
|
|
|
|
// ==================== 全面统计 ====================
|
|
|
|
function get_full_stats($layer, $module) {
|
|
global $zbp;
|
|
|
|
if (!in_array($layer, ['basic', 'detail', 'full', 'hot'])) {
|
|
$layer = 'basic';
|
|
}
|
|
|
|
$data = array();
|
|
|
|
if (!empty($module)) {
|
|
switch ($module) {
|
|
case 'recipe': $data['recipe'] = get_recipe_stats($layer); break;
|
|
case 'ingredient': $data['ingredient'] = get_ingredient_stats($layer); break;
|
|
case 'category': $data['category'] = get_category_stats($layer); break;
|
|
case 'tag': $data['tag'] = get_tag_stats($layer); break;
|
|
case 'user': $data['user'] = get_user_stats($layer); break;
|
|
case 'nutrition': $data['nutrition'] = get_nutrition_stats($layer); break;
|
|
default: return array('code' => 400, 'message' => '无效的模块参数', 'data' => null);
|
|
}
|
|
} else {
|
|
$data['basic'] = get_basic_stats();
|
|
|
|
if ($layer === 'detail' || $layer === 'full') {
|
|
$data['recipe'] = get_recipe_stats($layer);
|
|
$data['ingredient'] = get_ingredient_stats($layer);
|
|
$data['category'] = get_category_stats($layer);
|
|
$data['tag'] = get_tag_stats($layer);
|
|
$data['user'] = get_user_stats($layer);
|
|
}
|
|
|
|
if ($layer === 'full') {
|
|
$data['nutrition'] = get_nutrition_stats($layer);
|
|
$data['time_analysis'] = get_time_analysis();
|
|
}
|
|
}
|
|
|
|
return array('code' => 200, 'message' => 'success', 'data' => $data);
|
|
}
|
|
|
|
function get_basic_stats() {
|
|
global $zbp;
|
|
|
|
$tablePost = $zbp->db->dbpre . 'post';
|
|
$tableIngredient = $zbp->db->dbpre . 'ingredient_detail';
|
|
$tablePostStat = $zbp->db->dbpre . 'post_stat';
|
|
$tableIngredientStat = $zbp->db->dbpre . 'ingredient_stat';
|
|
|
|
return array(
|
|
'recipe' => array(
|
|
'total' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tablePost WHERE log_Type = 0 AND log_Status = 0")[0]['c'] ?? 0),
|
|
'views' => (int) ($zbp->db->Query("SELECT SUM(log_ViewNums) as v FROM $tablePost WHERE log_Type = 0")[0]['v'] ?? 0),
|
|
'likes' => (int) ($zbp->db->Query("SELECT SUM(like_nums) as l FROM $tablePostStat")[0]['l'] ?? 0),
|
|
'recommends' => (int) ($zbp->db->Query("SELECT SUM(recommend_nums) as r FROM $tablePostStat")[0]['r'] ?? 0)
|
|
),
|
|
'ingredient' => array(
|
|
'total' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tableIngredient")[0]['c'] ?? 0),
|
|
'views' => (int) ($zbp->db->Query("SELECT SUM(view_count) as v FROM $tableIngredient")[0]['v'] ?? 0),
|
|
'likes' => (int) ($zbp->db->Query("SELECT SUM(like_nums) as l FROM $tableIngredientStat")[0]['l'] ?? 0),
|
|
'recommends' => (int) ($zbp->db->Query("SELECT SUM(recommend_nums) as r FROM $tableIngredientStat")[0]['r'] ?? 0)
|
|
),
|
|
'category' => array('total' => count($zbp->categories)),
|
|
'tag' => array('total' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM " . $zbp->db->dbpre . "tag")[0]['c'] ?? 0)),
|
|
'user' => array('total' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM " . $zbp->db->dbpre . "member")[0]['c'] ?? 0))
|
|
);
|
|
}
|
|
|
|
function get_recipe_stats($layer) {
|
|
global $zbp;
|
|
|
|
$tablePost = $zbp->db->dbpre . 'post';
|
|
$tablePostStat = $zbp->db->dbpre . 'post_stat';
|
|
$tableRecipe = $zbp->db->dbpre . 'recipe';
|
|
|
|
$stats = array(
|
|
'total' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tablePost WHERE log_Type = 0 AND log_Status = 0")[0]['c'] ?? 0),
|
|
'views' => (int) ($zbp->db->Query("SELECT SUM(log_ViewNums) as v FROM $tablePost WHERE log_Type = 0")[0]['v'] ?? 0),
|
|
'likes' => (int) ($zbp->db->Query("SELECT SUM(like_nums) as l FROM $tablePostStat")[0]['l'] ?? 0),
|
|
'recommends' => (int) ($zbp->db->Query("SELECT SUM(recommend_nums) as r FROM $tablePostStat")[0]['r'] ?? 0)
|
|
);
|
|
|
|
if ($layer === 'detail' || $layer === 'full') {
|
|
$topViews = $zbp->db->Query("SELECT log_ID, log_Title, log_ViewNums FROM $tablePost WHERE log_Type = 0 AND log_Status = 0 ORDER BY log_ViewNums DESC LIMIT 10");
|
|
$stats['top_views'] = array();
|
|
foreach ($topViews as $row) {
|
|
$stats['top_views'][] = array('id' => (int) $row['log_ID'], 'title' => $row['log_Title'], 'views' => (int) $row['log_ViewNums']);
|
|
}
|
|
|
|
$topLikes = $zbp->db->Query("SELECT p.log_ID, p.log_Title, s.like_nums FROM $tablePost p JOIN $tablePostStat s ON p.log_ID = s.log_id WHERE p.log_Type = 0 ORDER BY s.like_nums DESC LIMIT 10");
|
|
$stats['top_likes'] = array();
|
|
foreach ($topLikes as $row) {
|
|
$stats['top_likes'][] = array('id' => (int) $row['log_ID'], 'title' => $row['log_Title'], 'likes' => (int) $row['like_nums']);
|
|
}
|
|
}
|
|
|
|
return $stats;
|
|
}
|
|
|
|
function get_ingredient_stats($layer) {
|
|
global $zbp;
|
|
|
|
$tableIngredient = $zbp->db->dbpre . 'ingredient_detail';
|
|
$tableIngredientStat = $zbp->db->dbpre . 'ingredient_stat';
|
|
|
|
$stats = array(
|
|
'total' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tableIngredient")[0]['c'] ?? 0),
|
|
'views' => (int) ($zbp->db->Query("SELECT SUM(view_count) as v FROM $tableIngredient")[0]['v'] ?? 0),
|
|
'likes' => (int) ($zbp->db->Query("SELECT SUM(like_nums) as l FROM $tableIngredientStat")[0]['l'] ?? 0),
|
|
'recommends' => (int) ($zbp->db->Query("SELECT SUM(recommend_nums) as r FROM $tableIngredientStat")[0]['r'] ?? 0)
|
|
);
|
|
|
|
if ($layer === 'detail' || $layer === 'full') {
|
|
$topViews = $zbp->db->Query("SELECT ingredient_id, name, view_count FROM $tableIngredient ORDER BY view_count DESC LIMIT 10");
|
|
$stats['top_views'] = array();
|
|
foreach ($topViews as $row) {
|
|
$stats['top_views'][] = array('id' => (int) $row['ingredient_id'], 'name' => $row['name'], 'views' => (int) $row['view_count']);
|
|
}
|
|
}
|
|
|
|
return $stats;
|
|
}
|
|
|
|
function get_category_stats($layer) {
|
|
global $zbp;
|
|
|
|
$tableCategory = $zbp->db->dbpre . 'category';
|
|
|
|
$stats = array(
|
|
'total' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tableCategory")[0]['c'] ?? 0),
|
|
'root_count' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tableCategory WHERE cate_ParentID = 0")[0]['c'] ?? 0)
|
|
);
|
|
|
|
return $stats;
|
|
}
|
|
|
|
function get_tag_stats($layer) {
|
|
global $zbp;
|
|
|
|
$tableTag = $zbp->db->dbpre . 'tag';
|
|
|
|
$stats = array(
|
|
'total' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tableTag")[0]['c'] ?? 0),
|
|
'used_count' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tableTag WHERE tag_Count > 0")[0]['c'] ?? 0)
|
|
);
|
|
|
|
return $stats;
|
|
}
|
|
|
|
function get_user_stats($layer) {
|
|
global $zbp;
|
|
|
|
$tableMember = $zbp->db->dbpre . 'member';
|
|
|
|
return array('total' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tableMember")[0]['c'] ?? 0));
|
|
}
|
|
|
|
function get_nutrition_stats($layer) {
|
|
global $zbp;
|
|
|
|
$tableNutrition = $zbp->db->dbpre . 'recipe_nutrition';
|
|
|
|
return array(
|
|
'total_records' => (int) ($zbp->db->Query("SELECT COUNT(*) as c FROM $tableNutrition")[0]['c'] ?? 0),
|
|
'unique_nutrients' => (int) ($zbp->db->Query("SELECT COUNT(DISTINCT name) as c FROM $tableNutrition")[0]['c'] ?? 0)
|
|
);
|
|
}
|
|
|
|
function get_time_analysis() {
|
|
global $zbp;
|
|
|
|
$tablePost = $zbp->db->dbpre . 'post';
|
|
|
|
$byMonth = $zbp->db->Query("SELECT FROM_UNIXTIME(log_PostTime, '%Y-%m') as month, COUNT(*) as c FROM $tablePost WHERE log_Type = 0 GROUP BY month ORDER BY month DESC LIMIT 12");
|
|
$stats['recipe_by_month'] = array();
|
|
foreach ($byMonth as $row) {
|
|
$stats['recipe_by_month'][] = array('month' => $row['month'], 'count' => (int) $row['c']);
|
|
}
|
|
|
|
return $stats;
|
|
}
|
|
|
|
// ==================== 热门统计 ====================
|
|
|
|
function get_hot_stats($period) {
|
|
global $zbp;
|
|
|
|
$limit = (int) ($_GET['limit'] ?? 20);
|
|
$limit = max(1, min(100, $limit));
|
|
|
|
$data = array();
|
|
|
|
if ($period === 'today') {
|
|
$data = get_period_hot('today', $limit);
|
|
} elseif ($period === 'month') {
|
|
$data = get_period_hot('month', $limit);
|
|
} else {
|
|
$data = array(
|
|
'today' => get_period_hot('today', $limit),
|
|
'month' => get_period_hot('month', $limit),
|
|
'total' => get_period_hot('total', $limit)
|
|
);
|
|
}
|
|
|
|
return array('code' => 200, 'message' => 'success', 'data' => $data);
|
|
}
|
|
|
|
function get_period_hot($period, $limit) {
|
|
global $zbp;
|
|
|
|
$tablePost = $zbp->db->dbpre . 'post';
|
|
$tablePostStat = $zbp->db->dbpre . 'post_stat';
|
|
$tableIngredient = $zbp->db->dbpre . 'ingredient_detail';
|
|
$tableIngredientStat = $zbp->db->dbpre . 'ingredient_stat';
|
|
$tableRecipeLog = $zbp->db->dbpre . 'recipe_stat_log';
|
|
$tableIngredientLog = $zbp->db->dbpre . 'ingredient_stat_log';
|
|
|
|
$data = array();
|
|
|
|
if ($period === 'total') {
|
|
$recipeViewSql = "SELECT p.log_ID as id, p.log_Title as name, p.log_ViewNums as count FROM $tablePost p WHERE p.log_Type = 0 AND p.log_Status = 0 ORDER BY p.log_ViewNums DESC LIMIT $limit";
|
|
$recipeLikeSql = "SELECT p.log_ID as id, p.log_Title as name, COALESCE(s.like_nums, 0) as count FROM $tablePost p LEFT JOIN $tablePostStat s ON p.log_ID = s.log_id WHERE p.log_Type = 0 ORDER BY count DESC LIMIT $limit";
|
|
|
|
$data['recipe_view'] = format_hot_list($zbp->db->Query($recipeViewSql));
|
|
$data['recipe_like'] = format_hot_list($zbp->db->Query($recipeLikeSql));
|
|
|
|
$ingredientViewSql = "SELECT ingredient_id as id, name, view_count as count FROM $tableIngredient ORDER BY view_count DESC LIMIT $limit";
|
|
$data['ingredient_view'] = format_hot_list($zbp->db->Query($ingredientViewSql));
|
|
} elseif ($period === 'today') {
|
|
$today = date('Y-m-d');
|
|
$recipeLogSql = "SELECT l.log_id as id, p.log_Title as name, l.view_count as count FROM $tableRecipeLog l LEFT JOIN $tablePost p ON l.log_id = p.log_ID WHERE l.stat_date = '$today' ORDER BY l.view_count DESC LIMIT $limit";
|
|
$data['recipe_view'] = format_hot_list($zbp->db->Query($recipeLogSql));
|
|
} elseif ($period === 'month') {
|
|
$monthStart = date('Y-m-01');
|
|
$monthEnd = date('Y-m-t');
|
|
$recipeLogSql = "SELECT l.log_id as id, p.log_Title as name, SUM(l.view_count) as count FROM $tableRecipeLog l LEFT JOIN $tablePost p ON l.log_id = p.log_ID WHERE l.stat_date >= '$monthStart' AND l.stat_date <= '$monthEnd' GROUP BY l.log_id ORDER BY count DESC LIMIT $limit";
|
|
$data['recipe_view'] = format_hot_list($zbp->db->Query($recipeLogSql));
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
function format_hot_list($results) {
|
|
$list = array();
|
|
foreach ($results as $row) {
|
|
$list[] = array('id' => (int) $row['id'], 'name' => $row['name'] ?? '未知', 'count' => (int) ($row['count'] ?? 0));
|
|
}
|
|
return $list;
|
|
}
|
|
|
|
// ==================== 在线统计 ====================
|
|
|
|
function get_online_stats() {
|
|
$data = load_online_data();
|
|
$timeOnline = calculate_time_online($data);
|
|
|
|
return array(
|
|
'code' => 200,
|
|
'message' => 'success',
|
|
'data' => array(
|
|
'online_total' => count($data['users']),
|
|
'online_10min' => $timeOnline['last_10min'],
|
|
'online_1hour' => $timeOnline['last_1hour'],
|
|
'platforms' => $data['platforms'],
|
|
'pages' => $data['pages'],
|
|
'last_update' => date('Y-m-d H:i:s', $data['last_clean'] ?? time())
|
|
)
|
|
);
|
|
}
|
|
|
|
function update_heartbeat() {
|
|
$platform = strtolower(trim($_GET['platform'] ?? 'web'));
|
|
$page = strtolower(trim($_GET['page'] ?? 'home'));
|
|
$dataType = strtolower(trim($_GET['data_type'] ?? ''));
|
|
$dataId = (int) ($_GET['data_id'] ?? 0);
|
|
|
|
$validPlatforms = array('web', 'ios', 'android', 'wechat', 'miniprogram', 'other');
|
|
if (!in_array($platform, $validPlatforms)) $platform = 'other';
|
|
|
|
$data = load_online_data();
|
|
$userId = get_user_id();
|
|
$now = time();
|
|
|
|
if (rand(1, 20) === 1) {
|
|
$timeout = 3600;
|
|
$newUsers = array();
|
|
foreach ($data['users'] as $uid => $user) {
|
|
if ($now - $user['last_time'] <= $timeout) $newUsers[$uid] = $user;
|
|
}
|
|
$data['users'] = $newUsers;
|
|
}
|
|
|
|
$data['users'][$userId] = array(
|
|
'platform' => $platform,
|
|
'page' => $page,
|
|
'data_type' => $dataType,
|
|
'data_id' => $dataId,
|
|
'first_time' => isset($data['users'][$userId]) ? $data['users'][$userId]['first_time'] : $now,
|
|
'last_time' => $now
|
|
);
|
|
|
|
$platforms = array();
|
|
$pages = array();
|
|
foreach ($data['users'] as $user) {
|
|
$p = $user['platform'] ?? 'unknown';
|
|
$platforms[$p] = isset($platforms[$p]) ? $platforms[$p] + 1 : 1;
|
|
$pg = $user['page'] ?? 'unknown';
|
|
$pages[$pg] = isset($pages[$pg]) ? $pages[$pg] + 1 : 1;
|
|
}
|
|
|
|
$data['platforms'] = $platforms;
|
|
$data['pages'] = $pages;
|
|
$data['total'] = count($data['users']);
|
|
$data['last_clean'] = $now;
|
|
|
|
save_online_data($data);
|
|
|
|
$timeOnline = calculate_time_online($data);
|
|
|
|
return array(
|
|
'code' => 200,
|
|
'message' => '心跳更新成功',
|
|
'data' => array(
|
|
'user_id' => $userId,
|
|
'online_total' => $data['total'],
|
|
'online_10min' => $timeOnline['last_10min'],
|
|
'online_1hour' => $timeOnline['last_1hour'],
|
|
'heartbeat_interval' => 30
|
|
)
|
|
);
|
|
}
|
|
|
|
function get_user_id() {
|
|
$ip = get_client_ip();
|
|
$ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
|
$sessionId = isset($_GET['session_id']) ? $_GET['session_id'] : '';
|
|
if (empty($sessionId)) $sessionId = md5($ip . $ua);
|
|
return $sessionId;
|
|
}
|
|
|
|
function get_client_ip() {
|
|
$ip = '';
|
|
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
|
elseif (isset($_SERVER['HTTP_CLIENT_IP'])) $ip = $_SERVER['HTTP_CLIENT_IP'];
|
|
elseif (isset($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR'];
|
|
$ip = trim(explode(',', $ip)[0]);
|
|
return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '0.0.0.0';
|
|
}
|
|
|
|
function load_online_data() {
|
|
$file = dirname(__FILE__) . '/cache/online/online_users.json';
|
|
if (file_exists($file)) {
|
|
$content = file_get_contents($file);
|
|
$data = json_decode($content, true);
|
|
return is_array($data) ? $data : array('users' => array(), 'platforms' => array(), 'pages' => array(), 'total' => 0, 'last_clean' => time());
|
|
}
|
|
return array('users' => array(), 'platforms' => array(), 'pages' => array(), 'total' => 0, 'last_clean' => time());
|
|
}
|
|
|
|
function save_online_data($data) {
|
|
$cacheDir = dirname(__FILE__) . '/cache/online/';
|
|
if (!is_dir($cacheDir)) @mkdir($cacheDir, 0755, true);
|
|
$file = $cacheDir . 'online_users.json';
|
|
file_put_contents($file, json_encode($data, JSON_UNESCAPED_UNICODE));
|
|
}
|
|
|
|
function calculate_time_online($data) {
|
|
$now = time();
|
|
$tenMinAgo = $now - 600;
|
|
$oneHourAgo = $now - 3600;
|
|
$tenMinCount = 0;
|
|
$oneHourCount = 0;
|
|
foreach ($data['users'] as $user) {
|
|
$lastTime = $user['last_time'] ?? 0;
|
|
if ($lastTime >= $tenMinAgo) $tenMinCount++;
|
|
if ($lastTime >= $oneHourAgo) $oneHourCount++;
|
|
}
|
|
return array('last_10min' => $tenMinCount, 'last_1hour' => $oneHourCount);
|
|
}
|
|
|
|
// ==================== 请求统计 ====================
|
|
|
|
function get_request_stats() {
|
|
$data = load_request_stats();
|
|
$lastHour = calculate_last_hour_requests();
|
|
|
|
$today = date('Y-m-d');
|
|
if ($data['today_date'] !== $today) {
|
|
$data['today'] = 0;
|
|
$data['today_date'] = $today;
|
|
$data['hourly'] = array();
|
|
save_request_stats($data);
|
|
}
|
|
|
|
return array(
|
|
'code' => 200,
|
|
'message' => 'success',
|
|
'data' => array(
|
|
'total' => $data['total'],
|
|
'today' => $data['today'],
|
|
'last_hour' => $lastHour,
|
|
'start_date' => $data['start_date'],
|
|
'days' => floor((time() - strtotime($data['start_date'])) / 86400) + 1,
|
|
'avg_daily' => $data['total'] > 0 ? round($data['total'] / max(1, floor((time() - strtotime($data['start_date'])) / 86400) + 1)) : 0,
|
|
'apis' => $data['apis']
|
|
)
|
|
);
|
|
}
|
|
|
|
function load_request_stats() {
|
|
$file = dirname(__FILE__) . '/cache/stats/request_stats.json';
|
|
if (file_exists($file)) {
|
|
$content = file_get_contents($file);
|
|
$data = json_decode($content, true);
|
|
return is_array($data) ? $data : array('total' => 0, 'today' => 0, 'today_date' => date('Y-m-d'), 'apis' => array(), 'hourly' => array(), 'start_date' => date('Y-m-d'));
|
|
}
|
|
return array('total' => 0, 'today' => 0, 'today_date' => date('Y-m-d'), 'apis' => array(), 'hourly' => array(), 'start_date' => date('Y-m-d'));
|
|
}
|
|
|
|
function save_request_stats($data) {
|
|
$cacheDir = dirname(__FILE__) . '/cache/stats/';
|
|
if (!is_dir($cacheDir)) @mkdir($cacheDir, 0755, true);
|
|
$file = $cacheDir . 'request_stats.json';
|
|
file_put_contents($file, json_encode($data, JSON_UNESCAPED_UNICODE));
|
|
}
|
|
|
|
function calculate_last_hour_requests() {
|
|
$file = dirname(__FILE__) . '/cache/stats/minute_stats.json';
|
|
if (!file_exists($file)) return 0;
|
|
$content = file_get_contents($file);
|
|
$minuteStats = json_decode($content, true);
|
|
if (!is_array($minuteStats)) return 0;
|
|
$total = 0;
|
|
foreach ($minuteStats as $item) $total += $item['count'] ?? 0;
|
|
return $total;
|
|
}
|