Initial commit - TPU Survey System with Google Forms & Certificate Generator

This commit is contained in:
pongpon pitisuk
2026-09-12 11:56:34 +07:00
commit 72eb7cd0c8
355 changed files with 117012 additions and 0 deletions
+169
View File
@@ -0,0 +1,169 @@
<?php
/**
* Import Responses API (from CSV / Excel exported from Google Forms)
* POST ?survey_id=X
*/
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../config/auth.php';
header('Content-Type: application/json; charset=utf-8');
requireLogin();
$surveyId = (int)($_GET['survey_id'] ?? $_POST['survey_id'] ?? 0);
if (!$surveyId) {
jsonResponse(['error' => 'Missing survey_id'], 400);
}
$db = getDB();
// Verify access
if (!isAdmin()) {
$stmt = $db->prepare("SELECT user_id FROM surveys WHERE id = ?");
$stmt->execute([$surveyId]);
$s = $stmt->fetch();
if (!$s || $s['user_id'] != $_SESSION['user_id']) {
jsonResponse(['error' => 'ไม่มีสิทธิ์เข้าถึงแบบสอบถามนี้'], 403);
}
}
// Check uploaded file
if (!isset($_FILES['csv_file']) || $_FILES['csv_file']['error'] !== UPLOAD_ERR_OK) {
jsonResponse(['error' => 'กรุณาอัปโหลดไฟล์ CSV คำตอบจาก Google Forms'], 400);
}
$filePath = $_FILES['csv_file']['tmp_name'];
// Read CSV
$handle = fopen($filePath, 'r');
if (!$handle) {
jsonResponse(['error' => 'ไม่สามารถเปิดไฟล์ CSV ได้'], 500);
}
// Check UTF-8 BOM or UTF-16
$bom = fread($handle, 3);
if ($bom !== "\xEF\xBB\xBF") {
rewind($handle);
}
// Get Headers (Row 1)
$headers = fgetcsv($handle, 0, ",");
if (!$headers) {
fclose($handle);
jsonResponse(['error' => 'ไฟล์ CSV ไม่มีข้อมูลหรือรูปแบบไม่ถูกต้อง'], 400);
}
// Clean headers
$cleanHeaders = array_map(function($h) {
return trim(preg_replace('/\s+/', ' ', $h));
}, $headers);
// Fetch all questions for this survey
$stmt = $db->prepare("
SELECT q.id, q.question_text, q.question_type
FROM survey_questions q
JOIN survey_sections s ON q.section_id = s.id
WHERE s.survey_id = ?
ORDER BY s.section_number, q.order_num
");
$stmt->execute([$surveyId]);
$questions = $stmt->fetchAll();
if (empty($questions)) {
fclose($handle);
jsonResponse(['error' => 'ไม่พบข้อคำถามในแบบสอบถามนี้'], 400);
}
// Map CSV Column Index -> question_id
$colToQuestionMap = [];
function normalizeText($str) {
$str = mb_strtolower($str, 'UTF-8');
// Remove leading numbers or prefix like "1. ", "ข้อ 1. "
$str = preg_replace('/^[\d๑-๙]+[\.\)\s\-:\x{00A0}]*/u', '', $str);
return trim($str);
}
foreach ($cleanHeaders as $colIdx => $headerText) {
if (empty($headerText) || strtolower($headerText) === 'timestamp' || strtolower($headerText) === 'ประทับเวลา') {
continue;
}
$normHeader = normalizeText($headerText);
// Try exact or normalized matching against survey questions
foreach ($questions as $q) {
$normQText = normalizeText($q['question_text']);
if ($normHeader === $normQText || strpos($normHeader, $normQText) !== false || strpos($normQText, $normHeader) !== false) {
$colToQuestionMap[$colIdx] = $q['id'];
break;
}
}
}
// Fallback: If column mapping count is low, map columns sequentially to questions
if (count($colToQuestionMap) === 0) {
$qIdx = 0;
foreach ($cleanHeaders as $colIdx => $headerText) {
if (strtolower($headerText) === 'timestamp' || strtolower($headerText) === 'ประทับเวลา') continue;
if (isset($questions[$qIdx])) {
$colToQuestionMap[$colIdx] = $questions[$qIdx]['id'];
$qIdx++;
}
}
}
// Process Rows
$importedCount = 0;
$db->beginTransaction();
try {
while (($row = fgetcsv($handle, 0, ",")) !== false) {
if (empty(array_filter($row))) continue; // Skip empty lines
// Extract timestamp or use now
$submittedAt = date('Y-m-d H:i:s');
if (!empty($row[0])) {
$ts = strtotime($row[0]);
if ($ts !== false) {
$submittedAt = date('Y-m-d H:i:s', $ts);
}
}
// Insert into survey_responses
$stmtResp = $db->prepare("INSERT INTO survey_responses (survey_id, respondent_info, submitted_at) VALUES (?, ?, ?)");
$stmtResp->execute([
$surveyId,
json_encode(['imported' => true, 'source' => 'google_forms_csv'], JSON_UNESCAPED_UNICODE),
$submittedAt
]);
$responseId = $db->lastInsertId();
// Insert answers
foreach ($colToQuestionMap as $colIdx => $qId) {
$val = isset($row[$colIdx]) ? trim($row[$colIdx]) : '';
if ($val !== '') {
$stmtAns = $db->prepare("INSERT INTO response_answers (response_id, question_id, answer_value) VALUES (?, ?, ?)");
$stmtAns->execute([$responseId, $qId, $val]);
}
}
$importedCount++;
}
$db->commit();
fclose($handle);
jsonResponse([
'success' => true,
'message' => "นำเข้าข้อมูลคำตอบสำเร็จจำนวน $importedCount รายการ",
'imported_count' => $importedCount,
'mapped_questions' => count($colToQuestionMap)
]);
} catch (Exception $e) {
$db->rollBack();
fclose($handle);
jsonResponse(['error' => 'เกิดข้อผิดพลาดในการบันทึกคำตอบ: ' . $e->getMessage()], 500);
}