|
|
<?php |
|
|
declare(strict_types=1); |
|
|
|
|
|
require_once __DIR__ . '/src/Bootstrap.php'; |
|
|
\SoftEdge\Env::load(__DIR__); |
|
|
\SoftEdge\Bootstrap::init(); |
|
|
|
|
|
use SoftEdge\Response; |
|
|
use SoftEdge\Validation; |
|
|
use SoftEdge\AuthService; |
|
|
use SoftEdge\RateLimiter; |
|
|
use SoftEdge\DB; |
|
|
use PDO; |
|
|
|
|
|
|
|
|
if (!headers_sent()) { |
|
|
header('Content-Type: application/json; charset=utf-8'); |
|
|
header('X-Powered-By: SoftEdge'); |
|
|
} |
|
|
|
|
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { |
|
|
header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); |
|
|
header('Access-Control-Allow-Headers: Content-Type, X-CSRF-Token, Authorization'); |
|
|
header('Access-Control-Max-Age: 86400'); |
|
|
http_response_code(204); |
|
|
exit; |
|
|
} |
|
|
|
|
|
|
|
|
$origin = $_SERVER['HTTP_ORIGIN'] ?? ''; |
|
|
$host = $_SERVER['HTTP_HOST'] ?? ''; |
|
|
if ($origin && str_contains($origin, $host)) { |
|
|
header('Access-Control-Allow-Origin: ' . $origin); |
|
|
header('Vary: Origin'); |
|
|
header('Access-Control-Allow-Credentials: true'); |
|
|
} |
|
|
|
|
|
function path(): string { |
|
|
$uri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/'; |
|
|
|
|
|
if (isset($_GET['r'])) { |
|
|
$r = '/' . ltrim((string)$_GET['r'], '/'); |
|
|
return $r; |
|
|
} |
|
|
if (preg_match('#/api(?:\.php)?(.*)$#', $uri, $m)) { |
|
|
return $m[1] ? (string)$m[1] : '/'; |
|
|
} |
|
|
return $uri; |
|
|
} |
|
|
|
|
|
function json_body(): array { |
|
|
$raw = file_get_contents('php://input'); |
|
|
$data = json_decode((string)$raw, true); |
|
|
return is_array($data) ? $data : []; |
|
|
} |
|
|
|
|
|
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET'); |
|
|
$route = rtrim(path(), '/') ?: '/'; |
|
|
|
|
|
try { |
|
|
switch (true) { |
|
|
case $method === 'GET' && $route === '/health': |
|
|
Response::json([ |
|
|
'ok' => true, |
|
|
'time' => date('c'), |
|
|
'app' => 'SoftEdge API', |
|
|
'env' => \SoftEdge\Env::get('APP_ENV', 'production'), |
|
|
]); |
|
|
break; |
|
|
|
|
|
case $method === 'POST' && $route === '/auth/login': |
|
|
$body = json_body(); |
|
|
$csrf = (string)($body['csrf'] ?? ($_SERVER['HTTP_X_CSRF_TOKEN'] ?? '')); |
|
|
if (!\SoftEdge\Csrf::validate($csrf)) { |
|
|
Response::json(['ok' => false, 'error' => 'CSRF inválido'], 400); |
|
|
break; |
|
|
} |
|
|
$email = trim((string)($body['email'] ?? '')); |
|
|
$password = (string)($body['password'] ?? ''); |
|
|
if (!Validation::email($email)) { |
|
|
Response::json(['ok' => false, 'error' => 'Email inválido'], 422); |
|
|
break; |
|
|
} |
|
|
$res = AuthService::login($email, $password); |
|
|
Response::json($res, (int)($res['status'] ?? 200)); |
|
|
break; |
|
|
|
|
|
case $method === 'POST' && $route === '/auth/logout': |
|
|
AuthService::logout(); |
|
|
Response::json(['ok' => true]); |
|
|
break; |
|
|
|
|
|
case $method === 'POST' && $route === '/contact': |
|
|
$body = json_body(); |
|
|
$csrf = (string)($body['csrf'] ?? ($_SERVER['HTTP_X_CSRF_TOKEN'] ?? '')); |
|
|
if (!\SoftEdge\Csrf::validate($csrf)) { |
|
|
Response::json(['ok' => false, 'error' => 'CSRF inválido'], 400); |
|
|
break; |
|
|
} |
|
|
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown'; |
|
|
if (!RateLimiter::allow('contact:' . $ip, \SoftEdge\Env::int('RATE_LIMIT_CONTACT', 3), 3600)) { |
|
|
Response::json(['ok' => false, 'error' => 'Muitas solicitações. Tente mais tarde.'], 429); |
|
|
break; |
|
|
} |
|
|
$name = trim((string)($body['name'] ?? '')); |
|
|
$email = trim((string)($body['email'] ?? '')); |
|
|
$message = trim((string)($body['message'] ?? '')); |
|
|
$phone = trim((string)($body['phone'] ?? '')); |
|
|
$company = trim((string)($body['company'] ?? '')); |
|
|
$subject = trim((string)($body['subject'] ?? '')); |
|
|
|
|
|
$errors = Validation::required(['name' => $name, 'email' => $email, 'message' => $message], ['name','email','message']); |
|
|
if (!empty($errors) || !Validation::email($email)) { |
|
|
$errors['email'] = $errors['email'] ?? (!Validation::email($email) ? 'Email inválido' : null); |
|
|
Response::json(['ok' => false, 'errors' => array_filter($errors)], 422); |
|
|
break; |
|
|
} |
|
|
|
|
|
$pdo = DB::pdo(); |
|
|
$stmt = $pdo->prepare('INSERT INTO contact_submissions (name, email, phone, company, subject, message, status) VALUES (:name,:email,:phone,:company,:subject,:message,\'new\')'); |
|
|
$stmt->execute([ |
|
|
':name' => $name, |
|
|
':email' => $email, |
|
|
':phone' => $phone ?: null, |
|
|
':company' => $company ?: null, |
|
|
':subject' => $subject ?: null, |
|
|
':message' => $message, |
|
|
]); |
|
|
Response::json(['ok' => true, 'id' => (int)$pdo->lastInsertId()], 201); |
|
|
break; |
|
|
|
|
|
default: |
|
|
Response::json(['ok' => false, 'error' => 'Rota não encontrada', 'route' => $route], 404); |
|
|
break; |
|
|
} |
|
|
} catch (Throwable $e) { |
|
|
Response::json([ |
|
|
'ok' => false, |
|
|
'error' => 'Erro interno', |
|
|
], 500); |
|
|
} |
|
|
|