API CARDIX
This commit is contained in:
238
api.php
Normal file
238
api.php
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Cardix Admin - MySQL Proxy API
|
||||||
|
* =========================================================
|
||||||
|
* INSTRUÇÕES DE DEPLOY:
|
||||||
|
* 1. Copie este arquivo para o seu servidor em 31.97.64.165
|
||||||
|
* 2. Coloque em um diretório acessível pelo Apache/Nginx
|
||||||
|
* Ex: /var/www/html/cardix-api/api.php
|
||||||
|
* 3. Acesse pelo browser: http://31.97.64.165/cardix-api/api.php?action=tables
|
||||||
|
* 4. Atualize a variável API_URL em src/lib/config.ts com a URL correta
|
||||||
|
* =========================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ---- Configurações ----
|
||||||
|
define('API_SECRET', 'cardix-admin-2024');
|
||||||
|
define('DB_HOST', 'localhost'); // Use 'localhost' se MySQL está no mesmo servidor
|
||||||
|
define('DB_NAME', 'cardix');
|
||||||
|
define('DB_USER', 'wander');
|
||||||
|
define('DB_PASS', 'DIpIYIp25O');
|
||||||
|
define('DB_PORT', 3306);
|
||||||
|
|
||||||
|
// ---- CORS Headers ----
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
|
||||||
|
header('Access-Control-Allow-Headers: Content-Type, X-API-Key');
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||||
|
http_response_code(204);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Autenticação por API Key ----
|
||||||
|
$apiKey = $_SERVER['HTTP_X_API_KEY'] ?? '';
|
||||||
|
if ($apiKey !== API_SECRET) {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(['error' => 'Não autorizado. Forneça o header X-API-Key.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Conexão PDO ----
|
||||||
|
try {
|
||||||
|
$pdo = new PDO(
|
||||||
|
"mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";port=" . DB_PORT . ";charset=utf8mb4",
|
||||||
|
DB_USER,
|
||||||
|
DB_PASS,
|
||||||
|
[
|
||||||
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||||
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||||
|
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => 'Falha na conexão com o banco de dados: ' . $e->getMessage()]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Helpers ----
|
||||||
|
function sanitizeIdentifier(string $name): string {
|
||||||
|
return preg_replace('/[^a-zA-Z0-9_]/', '', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPrimaryKey(PDO $pdo, string $table): string {
|
||||||
|
$stmt = $pdo->query("SHOW KEYS FROM `{$table}` WHERE Key_name = 'PRIMARY'");
|
||||||
|
$row = $stmt->fetch();
|
||||||
|
return $row ? $row['Column_name'] : 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
function jsonResponse(mixed $data, int $status = 200): void {
|
||||||
|
http_response_code($status);
|
||||||
|
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Roteamento ----
|
||||||
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
|
$action = $_GET['action'] ?? null;
|
||||||
|
$table = isset($_GET['table']) ? sanitizeIdentifier($_GET['table']) : null;
|
||||||
|
$id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
// ACTION: Listar todas as tabelas
|
||||||
|
if ($action === 'tables') {
|
||||||
|
$stmt = $pdo->query("SHOW TABLES");
|
||||||
|
jsonResponse($stmt->fetchAll(PDO::FETCH_COLUMN));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACTION: Schema de uma tabela (colunas + FKs)
|
||||||
|
if ($action === 'schema' && $table) {
|
||||||
|
$stmt = $pdo->query("DESCRIBE `{$table}`");
|
||||||
|
$columns = $stmt->fetchAll();
|
||||||
|
|
||||||
|
$fkStmt = $pdo->prepare("
|
||||||
|
SELECT COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
|
||||||
|
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_NAME = ?
|
||||||
|
AND REFERENCED_TABLE_NAME IS NOT NULL
|
||||||
|
");
|
||||||
|
$fkStmt->execute([$table]);
|
||||||
|
$fks = $fkStmt->fetchAll();
|
||||||
|
|
||||||
|
// Para cada FK, detecta a melhor coluna de exibição
|
||||||
|
$fkDisplay = [];
|
||||||
|
foreach ($fks as $fk) {
|
||||||
|
$refTable = $fk['REFERENCED_TABLE_NAME'];
|
||||||
|
$descStmt = $pdo->query("DESCRIBE `{$refTable}`");
|
||||||
|
$refCols = $descStmt->fetchAll();
|
||||||
|
|
||||||
|
$displayCol = null;
|
||||||
|
foreach ($refCols as $col) {
|
||||||
|
if ($col['Field'] !== $fk['REFERENCED_COLUMN_NAME'] &&
|
||||||
|
(strpos($col['Type'], 'varchar') !== false || strpos($col['Type'], 'text') !== false)) {
|
||||||
|
$displayCol = $col['Field'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$fkDisplay[$fk['COLUMN_NAME']] = [
|
||||||
|
'table' => $refTable,
|
||||||
|
'keyCol' => $fk['REFERENCED_COLUMN_NAME'],
|
||||||
|
'displayCol' => $displayCol ?? $fk['REFERENCED_COLUMN_NAME'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonResponse(['columns' => $columns, 'foreignKeys' => $fks, 'fkDisplay' => $fkDisplay]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACTION: Opções para campo FK (select dropdown)
|
||||||
|
if ($action === 'fk_options' && $table) {
|
||||||
|
$pkCol = sanitizeIdentifier($_GET['pk'] ?? 'id');
|
||||||
|
$labelCol = sanitizeIdentifier($_GET['label'] ?? $pkCol);
|
||||||
|
|
||||||
|
$stmt = $pdo->query(
|
||||||
|
"SELECT `{$pkCol}` AS `value`, `{$labelCol}` AS `label` FROM `{$table}` ORDER BY `{$labelCol}` LIMIT 500"
|
||||||
|
);
|
||||||
|
jsonResponse($stmt->fetchAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- CRUD ----
|
||||||
|
if (!$table) {
|
||||||
|
jsonResponse(['error' => 'Parâmetro "table" obrigatório'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pk = getPrimaryKey($pdo, $table);
|
||||||
|
|
||||||
|
switch ($method) {
|
||||||
|
|
||||||
|
// READ (listagem paginada ou registro único)
|
||||||
|
case 'GET':
|
||||||
|
if ($id !== null) {
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM `{$table}` WHERE `{$pk}` = ?");
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
$row = $stmt->fetch();
|
||||||
|
jsonResponse($row !== false ? $row : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
$page = max(1, intval($_GET['page'] ?? 1));
|
||||||
|
$limit = min(100, max(5, intval($_GET['limit'] ?? 10)));
|
||||||
|
$offset = ($page - 1) * $limit;
|
||||||
|
$search = trim($_GET['search'] ?? '');
|
||||||
|
|
||||||
|
// Busca simples em todas as colunas varchar
|
||||||
|
$whereClause = '';
|
||||||
|
$searchParams = [];
|
||||||
|
if ($search !== '') {
|
||||||
|
$descStmt = $pdo->query("DESCRIBE `{$table}`");
|
||||||
|
$cols = $descStmt->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||||
|
$conditions = [];
|
||||||
|
foreach ($cols as $col) {
|
||||||
|
$conditions[] = "`{$col}` LIKE ?";
|
||||||
|
$searchParams[] = "%{$search}%";
|
||||||
|
}
|
||||||
|
$whereClause = 'WHERE ' . implode(' OR ', $conditions);
|
||||||
|
}
|
||||||
|
|
||||||
|
$countStmt = $pdo->query("SELECT COUNT(*) FROM `{$table}` {$whereClause}");
|
||||||
|
if ($searchParams) {
|
||||||
|
$countStmt = $pdo->prepare("SELECT COUNT(*) FROM `{$table}` {$whereClause}");
|
||||||
|
$countStmt->execute($searchParams);
|
||||||
|
}
|
||||||
|
$total = (int) $countStmt->fetchColumn();
|
||||||
|
|
||||||
|
$dataStmt = $pdo->prepare("SELECT * FROM `{$table}` {$whereClause} LIMIT ? OFFSET ?");
|
||||||
|
$params = array_merge($searchParams, [$limit, $offset]);
|
||||||
|
$dataStmt->execute($params);
|
||||||
|
$data = $dataStmt->fetchAll();
|
||||||
|
|
||||||
|
jsonResponse([
|
||||||
|
'data' => $data,
|
||||||
|
'total' => $total,
|
||||||
|
'page' => $page,
|
||||||
|
'limit' => $limit,
|
||||||
|
'totalPages' => (int) ceil($total / $limit),
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// CREATE
|
||||||
|
case 'POST':
|
||||||
|
$body = json_decode(file_get_contents('php://input'), true);
|
||||||
|
if (!$body || !is_array($body)) {
|
||||||
|
jsonResponse(['error' => 'Body JSON inválido'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cols = array_keys($body);
|
||||||
|
$placeholders = implode(', ', array_fill(0, count($cols), '?'));
|
||||||
|
$colNames = '`' . implode('`, `', $cols) . '`';
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `{$table}` ({$colNames}) VALUES ({$placeholders})");
|
||||||
|
$stmt->execute(array_values($body));
|
||||||
|
jsonResponse(['id' => $pdo->lastInsertId(), 'message' => 'Registro criado com sucesso!']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// UPDATE
|
||||||
|
case 'PUT':
|
||||||
|
if ($id === null) jsonResponse(['error' => 'ID obrigatório para atualização'], 400);
|
||||||
|
|
||||||
|
$body = json_decode(file_get_contents('php://input'), true);
|
||||||
|
if (!$body || !is_array($body)) {
|
||||||
|
jsonResponse(['error' => 'Body JSON inválido'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sets = implode(', ', array_map(fn($col) => "`{$col}` = ?", array_keys($body)));
|
||||||
|
$stmt = $pdo->prepare("UPDATE `{$table}` SET {$sets} WHERE `{$pk}` = ?");
|
||||||
|
$stmt->execute([...array_values($body), $id]);
|
||||||
|
jsonResponse(['message' => 'Registro atualizado com sucesso!']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// DELETE
|
||||||
|
case 'DELETE':
|
||||||
|
if ($id === null) jsonResponse(['error' => 'ID obrigatório para exclusão'], 400);
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM `{$table}` WHERE `{$pk}` = ?");
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
jsonResponse(['message' => 'Registro excluído com sucesso!']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
jsonResponse(['error' => 'Método não permitido'], 405);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user