43 lines
1.5 KiB
PHP
43 lines
1.5 KiB
PHP
|
|
<?php
|
||
|
|
namespace App\Controllers;
|
||
|
|
|
||
|
|
/** Base for JSON endpoints: response envelope + IP throttle. Extends core \Controller. */
|
||
|
|
class JsonController extends \Controller
|
||
|
|
{
|
||
|
|
/** Emit { ok, data, error } with the right HTTP status, then stop. */
|
||
|
|
protected function json($data = null, int $status = 200, ?array $error = null): void
|
||
|
|
{
|
||
|
|
http_response_code($status);
|
||
|
|
header('Content-Type: application/json; charset=UTF-8');
|
||
|
|
echo json_encode([
|
||
|
|
'ok' => $error === null,
|
||
|
|
'data' => $data,
|
||
|
|
'error' => $error, // ['code' => ..., 'message' => ...] or null
|
||
|
|
]);
|
||
|
|
exit;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns true when the caller has EXCEEDED $max hits on $key within $window seconds.
|
||
|
|
* Reuses the api_requests table (no new table needed).
|
||
|
|
*/
|
||
|
|
protected function throttle(string $key, int $max, int $window): bool
|
||
|
|
{
|
||
|
|
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
||
|
|
$count = (int) \Db::getValue(
|
||
|
|
"SELECT COUNT(*) FROM `api_requests`
|
||
|
|
WHERE `requesting_ip` = ? AND `request` = ?
|
||
|
|
AND `created_date` > (NOW() - INTERVAL ? SECOND)",
|
||
|
|
[$ip, $key, $window]
|
||
|
|
);
|
||
|
|
\Db::insert('api_requests', [
|
||
|
|
'requesting_ip' => $ip,
|
||
|
|
'request' => $key,
|
||
|
|
'service' => 'foundation',
|
||
|
|
'domainURI' => $_SERVER['HTTP_HOST'] ?? '',
|
||
|
|
'created_date' => date('Y-m-d H:i:s'),
|
||
|
|
]);
|
||
|
|
return $count >= $max;
|
||
|
|
}
|
||
|
|
}
|