Files
turborfq/public/index.php
Michael Chus 66804814f1 debug: добавлена детальная отладка импорта CSV
- Добавлено логирование парсинга CSV на фронтенде
- Добавлено логирование отправляемых данных
- Добавлено детальное логирование в PHP бэкенде (каждая строка импорта)
- Улучшена обработка ошибок с выводом подробной информации
- Добавлен вывод SQL запросов при ошибках
2026-01-21 03:40:17 +03:00

272 lines
10 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use DI\Container;
require __DIR__ . '/../vendor/autoload.php';
session_start();
// DIконтейнер
$container = new Container();
AppFactory::setContainer($container);
$app = AppFactory::create();
// В dev включаем подробные ошибки (можно выключить в проде)
$app->addErrorMiddleware(true, true, true);
$container->set('db', function () {
return \App\Db::connectFromSession();
});
// --- ROUTES ---
// Статическая страница с фронтендом
$app->get('/', function (Request $request, Response $response) {
// Очень простой view встроен прямо здесь
$html = file_get_contents(__DIR__ . '/index.html'); // вынесем в отдельный файл ниже
$response->getBody()->write($html);
return $response;
});
// Логин: сохраняет логин/пароль MariaDB в сессии после проверки
$app->post('/api/login', function (Request $request, Response $response) {
$data = json_decode((string)$request->getBody(), true);
$user = $data['user'] ?? '';
$pass = $data['pass'] ?? '';
try {
\App\Db::testConnection($user, $pass);
$_SESSION['db_user'] = $user;
$_SESSION['db_pass'] = $pass;
$payload = ['ok' => true];
$status = 200;
} catch (\RuntimeException $e) {
$payload = ['ok' => false, 'error' => $e->getMessage()];
$status = 401;
}
$response->getBody()->write(json_encode($payload));
return $response->withHeader('Content-Type', 'application/json')
->withStatus($status);
});
// Middleware на /api/*: проверяем, что аутентифицированы
$app->add(function (Request $request, $handler) {
$path = $request->getUri()->getPath();
if (str_starts_with($path, '/api/') && $path !== '/api/login') {
if (empty($_SESSION['db_user']) || empty($_SESSION['db_pass'])) {
$res = new \Slim\Psr7\Response();
$res->getBody()->write(json_encode(['error' => 'Not authenticated']));
return $res->withStatus(401)->withHeader('Content-Type', 'application/json');
}
}
return $handler->handle($request);
});
// API: дерево схем/таблиц
$app->get('/api/tree', function (Request $request, Response $response) use ($container) {
$pdo = $container->get('db');
$meta = new \App\MetaService($pdo);
$tree = $meta->getSchemaTree();
$response->getBody()->write(json_encode($tree));
return $response->withHeader('Content-Type', 'application/json');
});
// API: метаданные таблицы
$app->get('/api/table/meta', function (Request $request, Response $response) use ($container) {
$params = $request->getQueryParams();
$schema = $params['schema'] ?? '';
$table = $params['table'] ?? '';
$pdo = $container->get('db');
$meta = new \App\MetaService($pdo);
$data = $meta->getTableMeta($schema, $table);
$response->getBody()->write(json_encode($data));
return $response->withHeader('Content-Type', 'application/json');
});
// API: данные таблицы
$app->post('/api/table/data', function (Request $request, Response $response) use ($container) {
$payload = json_decode((string)$request->getBody(), true);
$schema = $payload['schema'] ?? '';
$table = $payload['table'] ?? '';
$page = (int)($payload['page'] ?? 1);
$pageSize = (int)($payload['pageSize'] ?? 50);
$filters = $payload['filters'] ?? [];
$sort = $payload['sort'] ?? null;
$columns = $payload['columns'] ?? [];
// ✅ Логирование для отладки
error_log("Data request: page=$page, pageSize=$pageSize, filters=" . json_encode($filters));
$pdo = $container->get('db');
$ds = new \App\DataService($pdo);
$resData = $ds->fetchData($schema, $table, $columns, $page, $pageSize, $filters, $sort);
// ✅ Логирование ответа
error_log("Data response: " . json_encode([
'data_count' => count($resData['data']),
'last_page' => $resData['last_page'],
'current_page' => $resData['current_page'],
'total' => $resData['total']
]));
$response->getBody()->write(json_encode($resData));
return $response->withHeader('Content-Type', 'application/json');
});
// API: insert / update / delete
$app->post('/api/table/insert', function (Request $request, Response $response) use ($container) {
$payload = json_decode((string)$request->getBody(), true);
$pdo = $container->get('db');
$meta = new \App\MetaService($pdo);
$ds = new \App\DataService($pdo);
$schema = $payload['schema'];
$table = $payload['table'];
$row = $payload['row'];
$metaArr = $meta->getTableMeta($schema, $table);
$result = $ds->insertRow($schema, $table, $row, $metaArr['columns']);
$response->getBody()->write(json_encode($result));
return $response->withHeader('Content-Type', 'application/json');
});
$app->post('/api/table/update', function (Request $request, Response $response) use ($container) {
$payload = json_decode((string)$request->getBody(), true);
$pdo = $container->get('db');
$meta = new \App\MetaService($pdo);
$ds = new \App\DataService($pdo);
$schema = $payload['schema'];
$table = $payload['table'];
$row = $payload['row'];
$metaArr = $meta->getTableMeta($schema, $table);
$result = $ds->updateRow($schema, $table, $row, $metaArr['columns'], $metaArr['primaryKey']);
$response->getBody()->write(json_encode($result));
return $response->withHeader('Content-Type', 'application/json');
});
$app->post('/api/table/delete', function (Request $request, Response $response) use ($container) {
$payload = json_decode((string)$request->getBody(), true);
$pdo = $container->get('db');
$meta = new \App\MetaService($pdo);
$ds = new \App\DataService($pdo);
$schema = $payload['schema'];
$table = $payload['table'];
$row = $payload['row'];
$metaArr = $meta->getTableMeta($schema, $table);
$result = $ds->deleteRow($schema, $table, $row, $metaArr['primaryKey']);
$response->getBody()->write(json_encode($result));
return $response->withHeader('Content-Type', 'application/json');
});
// API: импорт CSV (массовая вставка)
$app->post('/api/table/import-csv', function (Request $request, Response $response) use ($container) {
error_log("\n========== ЗАПРОС НА ИМПОРТ CSV ==========");
$body = (string)$request->getBody();
error_log("Тело запроса (первые 1000 символов): " . substr($body, 0, 1000));
$payload = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log("ОШИБКА JSON: " . json_last_error_msg());
$response->getBody()->write(json_encode(['error' => 'Invalid JSON: ' . json_last_error_msg()]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
error_log("Декодированный payload: " . json_encode($payload, JSON_PRETTY_PRINT));
$pdo = $container->get('db');
$meta = new \App\MetaService($pdo);
$ds = new \App\DataService($pdo);
$schema = $payload['schema'] ?? '';
$table = $payload['table'] ?? '';
$rows = $payload['rows'] ?? [];
error_log("Schema: $schema");
error_log("Table: $table");
error_log("Количество строк: " . count($rows));
if (empty($schema) || empty($table)) {
error_log("ОШИБКА: пустая schema или table");
$response->getBody()->write(json_encode(['error' => 'Schema and table are required']));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
try {
$metaArr = $meta->getTableMeta($schema, $table);
error_log("Метаданные таблицы получены, столбцов: " . count($metaArr['columns']));
$result = $ds->insertMultipleRows($schema, $table, $rows, $metaArr['columns']);
error_log("Результат импорта: " . json_encode($result));
$response->getBody()->write(json_encode($result));
return $response->withHeader('Content-Type', 'application/json');
} catch (\Exception $e) {
error_log("КРИТИЧЕСКАЯ ОШИБКА: " . $e->getMessage());
error_log("Stack trace: " . $e->getTraceAsString());
$response->getBody()->write(json_encode([
'error' => $e->getMessage(),
'inserted' => 0,
'errors' => 1
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(500);
}
});
// API: экспорт CSV
$app->post('/api/table/export-csv', function (Request $request, Response $response) use ($container) {
$payload = json_decode((string)$request->getBody(), true);
$pdo = $container->get('db');
$ds = new \App\DataService($pdo);
$schema = $payload['schema'] ?? '';
$table = $payload['table'] ?? '';
$filters = $payload['filters'] ?? [];
$sort = $payload['sort'] ?? null;
$columns = $payload['columns'] ?? [];
$result = $ds->exportCSV($schema, $table, $columns, $filters, $sort);
$response->getBody()->write(json_encode($result));
return $response->withHeader('Content-Type', 'application/json');
});
// API: получить доступные значения для Foreign Key
$app->get('/api/fk-values', function (Request $request, Response $response) use ($container) {
$params = $request->getQueryParams();
$schema = $params['schema'] ?? '';
$table = $params['table'] ?? '';
$column = $params['column'] ?? '';
$pdo = $container->get('db');
// Получаем до 100 первых значений
$sql = "SELECT DISTINCT `{$column}` FROM `{$schema}`.`{$table}`
WHERE `{$column}` IS NOT NULL
ORDER BY `{$column}`
LIMIT 100";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$values = $stmt->fetchAll(PDO::FETCH_COLUMN);
$response->getBody()->write(json_encode(['values' => $values]));
return $response->withHeader('Content-Type', 'application/json');
});
$app->run();