Files
Ontime/backendpanel/application/helpers/quota_limiter_helper.php
2026-04-01 11:55:47 +07:00

68 lines
2.7 KiB
PHP
Executable File

<?php
defined('BASEPATH') or exit('No direct script access allowed');
/**
* Per-key quota limiter (e.g. per user, per token) for FCM, Maps, and other API usage.
* Uses database table quota_usage. Create with:
* CREATE TABLE IF NOT EXISTS quota_usage (
* id INT AUTO_INCREMENT PRIMARY KEY,
* key_name VARCHAR(255) NOT NULL,
* period_type VARCHAR(16) NOT NULL,
* period_value VARCHAR(32) NOT NULL,
* count INT UNSIGNED NOT NULL DEFAULT 0,
* updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
* UNIQUE KEY uk_key_period (key_name, period_type, period_value)
* );
*
* Callers pass limits; backend defaults often use FCM_LIMIT_PER_HOUR / FCM_LIMIT_PER_DAY from config.php.
*/
if (!function_exists('quota_limiter_allow')) {
/**
* Check and increment usage for the given key. Returns true if under limit, false if over.
* @param string $key Unique key (e.g. "fcm:recipient:".hash($token) or "maps:user:123")
* @param array $limits ['hour' => N, 'day' => N]. Use 0 to skip that period.
* @return bool True if request is allowed, false if over limit
*/
function quota_limiter_allow($key, $limits = array())
{
$CI = &get_instance();
if (!isset($CI->db) || !$CI->db->conn_id) {
return true;
}
$table = 'quota_usage';
$hour_period = date('Y-m-d-H');
$day_period = date('Y-m-d');
$hour_limit = isset($limits['hour']) ? (int) $limits['hour'] : 100;
$day_limit = isset($limits['day']) ? (int) $limits['day'] : 500;
$key_safe = substr($key, 0, 255);
foreach (array('hour' => array($hour_period, $hour_limit), 'day' => array($day_period, $day_limit)) as $period_type => $pair) {
list($period_value, $limit) = $pair;
if ($limit <= 0) {
continue;
}
$CI->db->query("
INSERT INTO {$table} (key_name, period_type, period_value, count, updated_at)
VALUES (?, ?, ?, 1, NOW())
ON DUPLICATE KEY UPDATE count = count + 1, updated_at = NOW()
", array($key_safe, $period_type, $period_value));
$row = $CI->db->query("
SELECT count FROM {$table}
WHERE key_name = ? AND period_type = ? AND period_value = ?
", array($key_safe, $period_type, $period_value))->row();
if ($row && (int) $row->count > $limit) {
return false;
}
}
return true;
}
}
if (!function_exists('quota_limiter_fcm_key')) {
function quota_limiter_fcm_key($recipient_identifier)
{
return 'fcm:' . substr(md5($recipient_identifier), 0, 32);
}
}