100 lines
3.0 KiB
PHP
100 lines
3.0 KiB
PHP
<?php
|
|
// api/helpers/response.php
|
|
|
|
function setCORSHeaders(): void {
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Vary: Origin');
|
|
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
|
|
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-API-Token');
|
|
header('X-Content-Type-Options: nosniff');
|
|
|
|
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
|
$allowed = false;
|
|
if ($origin !== '') {
|
|
$origin = trim($origin);
|
|
$allowedOrigins = parseAllowedOrigins(getenv('CORS_ALLOWED_ORIGINS') ?: '');
|
|
if (!empty($allowedOrigins)) {
|
|
$allowed = in_array($origin, $allowedOrigins, true);
|
|
} else {
|
|
$allowed = (bool)preg_match('/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/', $origin);
|
|
}
|
|
if ($allowed) {
|
|
header('Access-Control-Allow-Origin: ' . $origin);
|
|
}
|
|
}
|
|
|
|
if (getMethod() === 'OPTIONS') {
|
|
http_response_code(($origin !== '' && !$allowed) ? 403 : 204);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
function parseAllowedOrigins(string $raw): array {
|
|
$parts = array_map('trim', explode(',', $raw));
|
|
return array_values(array_filter($parts, static fn ($v) => $v !== ''));
|
|
}
|
|
|
|
function sendJSON(mixed $data, int $code = 200): void {
|
|
http_response_code($code);
|
|
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
exit;
|
|
}
|
|
|
|
function sendSuccess(mixed $data = null, string $message = 'OK', int $code = 200): void {
|
|
sendJSON(['status' => 'success', 'message' => $message, 'data' => $data], $code);
|
|
}
|
|
|
|
function sendError(string $message, int $code = 400): void {
|
|
sendJSON(['status' => 'error', 'message' => $message], $code);
|
|
}
|
|
|
|
function requireWriteAuth(string $method): void {
|
|
if (!in_array($method, ['POST', 'PUT', 'DELETE'], true)) {
|
|
return;
|
|
}
|
|
|
|
$expected = (string)(getenv('API_WRITE_TOKEN') ?: '');
|
|
if ($expected === '') {
|
|
return;
|
|
}
|
|
|
|
$provided = (string)($_SERVER['HTTP_X_API_TOKEN'] ?? '');
|
|
if ($provided === '') {
|
|
$auth = (string)($_SERVER['HTTP_AUTHORIZATION'] ?? '');
|
|
if (preg_match('/Bearer\s+(.+)/i', $auth, $m)) {
|
|
$provided = trim($m[1]);
|
|
}
|
|
}
|
|
|
|
if ($provided === '' || !hash_equals($expected, $provided)) {
|
|
sendError('Unauthorized', 401);
|
|
}
|
|
}
|
|
|
|
function executeOrFail(mysqli_stmt $stmt, string $defaultMessage = 'Operasi database gagal'): void {
|
|
if ($stmt->execute()) {
|
|
return;
|
|
}
|
|
|
|
$errno = $stmt->errno;
|
|
$error = $stmt->error;
|
|
error_log('DB stmt error [' . $errno . ']: ' . $error);
|
|
|
|
if ($errno === 1062) {
|
|
sendError('Data duplikat terdeteksi', 409);
|
|
}
|
|
if ($errno === 1451 || $errno === 1452) {
|
|
sendError('Relasi data tidak valid', 422);
|
|
}
|
|
sendError($defaultMessage, 500);
|
|
}
|
|
|
|
function getBody(): array {
|
|
$raw = file_get_contents('php://input');
|
|
$data = json_decode($raw, true);
|
|
return is_array($data) ? $data : [];
|
|
}
|
|
|
|
function getMethod(): string {
|
|
return strtoupper($_SERVER['REQUEST_METHOD']);
|
|
} |