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
+291
View File
@@ -0,0 +1,291 @@
<?php
/**
* Import Google Form API
* POST ?action=importFromUrl - Import survey structure from Google Form URL
* POST ?action=importFromJson - Import survey structure from JSON
*/
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../config/auth.php';
header('Content-Type: application/json; charset=utf-8');
requireLogin();
$action = $_GET['action'] ?? '';
switch ($action) {
case 'importFromUrl':
importFromUrl();
break;
case 'importFromJson':
importFromJson();
break;
default:
jsonResponse(['error' => 'Invalid action'], 400);
}
function importFromUrl() {
$input = json_decode(file_get_contents('php://input'), true);
$url = trim($input['url'] ?? '');
$projectId = !empty($input['project_id']) ? (int)$input['project_id'] : null;
if (empty($url)) {
jsonResponse(['error' => 'กรุณาระบุ URL หรือ Link ของ Google Form'], 400);
}
// Extract Form ID or viewform URL
if (!preg_match('/docs\.google\.com\/forms\/d\/e?\/([^\/]+)/i', $url, $matches) && !preg_match('/docs\.google\.com\/forms\/d\/([^\/]+)/i', $url, $matches)) {
jsonResponse(['error' => 'รูปแบบ URL ของ Google Form ไม่ถูกต้อง'], 400);
}
// Attempt to fetch the public viewform HTML
$fetchUrl = $url;
if (strpos($fetchUrl, '/viewform') === false && strpos($fetchUrl, '/edit') === false) {
$fetchUrl = rtrim($fetchUrl, '/') . '/viewform';
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $fetchUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$html = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200 || empty($html)) {
jsonResponse(['error' => 'ไม่สามารถดึงข้อมูลจาก Google Form URL นี้ได้ โปรดตรวจสอบว่าเปิดเป็นสาธารณะ (Public) หรือไม่'], 400);
}
// Parse FB_PUBLIC_LOAD_DATA_
if (!preg_match('/FB_PUBLIC_LOAD_DATA_\s*=\s*(.+?);<\/script>/s', $html, $dataMatches)) {
jsonResponse(['error' => 'ไม่พบโครงสร้างแบบสอบถามใน Google Form นี้'], 400);
}
$formData = json_decode($dataMatches[1], true);
if (!$formData || !isset($formData[1])) {
jsonResponse(['error' => 'โครงสร้างข้อมูล Google Form ไม่ถูกต้อง'], 400);
}
$parsedSurvey = parseGoogleFormData($formData);
$surveyId = saveParsedSurveyToDB($parsedSurvey, $projectId);
jsonResponse([
'success' => true,
'message' => 'นำเข้าโครงสร้างแบบสอบถามจาก Google Form เรียบร้อยแล้ว',
'survey_id' => $surveyId,
'title' => $parsedSurvey['title']
]);
}
function importFromJson() {
$input = json_decode(file_get_contents('php://input'), true);
$projectId = !empty($input['project_id']) ? (int)$input['project_id'] : null;
$surveyData = $input['survey_data'] ?? null;
if (!$surveyData || empty($surveyData['title'])) {
jsonResponse(['error' => 'ข้อมูล JSON ไม่ถูกต้อง หรือขาดชื่อแบบสอบถาม'], 400);
}
$surveyId = saveParsedSurveyToDB($surveyData, $projectId);
jsonResponse([
'success' => true,
'message' => 'นำเข้าแบบสอบถามเรียบร้อยแล้ว',
'survey_id' => $surveyId,
'title' => $surveyData['title']
]);
}
/**
* Helper: Parse Google Forms FB_PUBLIC_LOAD_DATA_ structure
*/
function parseGoogleFormData($data) {
$title = $data[1][8] ?? $data[1][1] ?? $data[3] ?? 'แบบสอบถามจาก Google Forms';
$description = $data[1][0] ?? '';
$rawItems = $data[1][1] ?? [];
$sections = [];
$currentSection = [
'section_number' => 1,
'title' => 'ส่วนที่ 1 ข้อมูลทั่วไป',
'description' => '',
'category' => 'general',
'questions' => []
];
$sectionCount = 1;
foreach ($rawItems as $item) {
if (!is_array($item)) continue;
$qTitle = $item[1] ?? '';
$qDesc = $item[2] ?? '';
$qTypeNum = $item[3] ?? 0;
$qDetails = $item[4][0] ?? [];
if (empty($qTitle) && $qTypeNum != 8) continue; // Skip empty items except section breaks
// Type 8 = Section Break in Google Forms
if ($qTypeNum == 8) {
if (!empty($currentSection['questions'])) {
$sections[] = $currentSection;
}
$sectionCount++;
$currentSection = [
'section_number' => $sectionCount,
'title' => $qTitle ?: ('ส่วนที่ ' . $sectionCount),
'description' => $qDesc,
'category' => 'rating',
'questions' => []
];
continue;
}
$qType = 'radio';
$options = [];
$scaleMin = 1;
$scaleMax = 5;
// Map Google Forms Item Type numbers:
// 0: Short Text, 1: Paragraph
// 2: Radio (Multiple Choice), 3: Dropdown, 4: Checkbox
// 5: Linear Scale (1-5)
// 7: Grid / Matrix
switch ($qTypeNum) {
case 0:
case 1:
$qType = 'text';
break;
case 2:
$qType = 'radio';
if (isset($qDetails[1]) && is_array($qDetails[1])) {
foreach ($qDetails[1] as $opt) {
if (isset($opt[0])) $options[] = $opt[0];
}
}
break;
case 3:
$qType = 'dropdown';
if (isset($qDetails[1]) && is_array($qDetails[1])) {
foreach ($qDetails[1] as $opt) {
if (isset($opt[0])) $options[] = $opt[0];
}
}
break;
case 4:
$qType = 'checkbox';
if (isset($qDetails[1]) && is_array($qDetails[1])) {
foreach ($qDetails[1] as $opt) {
if (isset($opt[0])) $options[] = $opt[0];
}
}
break;
case 5:
$qType = 'radio'; // Rating Scale
$scaleMin = 1;
$scaleMax = 5;
break;
default:
$qType = 'text';
break;
}
$isRequired = isset($qDetails[2]) && $qDetails[2] == 1 ? 1 : 0;
$questionObj = [
'question_text' => $qTitle,
'question_type' => $qType,
'is_required' => $isRequired,
'description' => $qDesc,
'options' => count($options) > 0 ? $options : null,
'scale_min' => $scaleMin,
'scale_max' => $scaleMax
];
$currentSection['questions'][] = $questionObj;
}
if (!empty($currentSection['questions'])) {
$sections[] = $currentSection;
}
if (empty($sections)) {
$sections[] = [
'section_number' => 1,
'title' => 'ส่วนที่ 1 ข้อมูลและข้อคำถาม',
'description' => 'นำเข้าจาก Google Forms',
'category' => 'general',
'questions' => []
];
}
return [
'title' => $title,
'description' => $description ?: 'แบบสอบถามที่นำเข้าจาก Google Forms',
'sections' => $sections
];
}
/**
* Save parsed survey structure into database
*/
function saveParsedSurveyToDB($parsedSurvey, $projectId = null) {
$db = getDB();
$uniqueLink = bin2hex(random_bytes(16));
$db->beginTransaction();
try {
$stmt = $db->prepare("INSERT INTO surveys (user_id, project_id, title, description, unique_link, status) VALUES (?, ?, ?, ?, ?, 'active')");
$stmt->execute([
$_SESSION['user_id'],
$projectId,
$parsedSurvey['title'],
$parsedSurvey['description'] ?? '',
$uniqueLink
]);
$surveyId = $db->lastInsertId();
$sections = $parsedSurvey['sections'] ?? [];
$secNum = 1;
foreach ($sections as $sec) {
$stmt = $db->prepare("INSERT INTO survey_sections (survey_id, section_number, title, description, category) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([
$surveyId,
$sec['section_number'] ?? $secNum,
$sec['title'] ?? ('ส่วนที่ ' . $secNum),
$sec['description'] ?? '',
$sec['category'] ?? 'rating'
]);
$sectionId = $db->lastInsertId();
$orderNum = 1;
foreach ($sec['questions'] as $q) {
$optionsJson = !empty($q['options']) ? json_encode($q['options'], JSON_UNESCAPED_UNICODE) : null;
$stmtQ = $db->prepare("INSERT INTO survey_questions (section_id, question_text, question_type, is_required, order_num, options, scale_min, scale_max, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmtQ->execute([
$sectionId,
$q['question_text'],
$q['question_type'] ?? 'radio',
$q['is_required'] ?? 1,
$orderNum++,
$optionsJson,
$q['scale_min'] ?? 1,
$q['scale_max'] ?? 5,
$q['description'] ?? null
]);
}
$secNum++;
}
$db->commit();
return $surveyId;
} catch (Exception $e) {
$db->rollBack();
jsonResponse(['error' => 'เกิดข้อผิดพลาดในการบันทึกแบบสอบถาม: ' . $e->getMessage()], 500);
}
}