Files
survey/api/import_google_form.php
T

372 lines
14 KiB
PHP

<?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');
if (php_sapi_name() !== 'cli') {
requireLogin();
}
if (isset($_GET['action'])) {
$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',
'headings' => [],
'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 && $qTypeNum != 7) continue;
// Type 8 = Section Break in Google Forms
if ($qTypeNum == 8) {
if (!empty($currentSection['questions']) || !empty($currentSection['headings'])) {
$sections[] = $currentSection;
}
$sectionCount++;
$currentSection = [
'section_number' => $sectionCount,
'title' => $qTitle ?: ('ตอนที่ ' . $sectionCount),
'description' => $qDesc ?: '',
'category' => 'rating',
'headings' => [],
'questions' => []
];
continue;
}
// Type 7 = Grid / Matrix (ตารางประเมินระดับความพึงพอใจ 5 ระดับ)
if ($qTypeNum == 7) {
$gridTitle = $qTitle ?: 'ด้านที่ประเมิน';
$gridDesc = $qDesc ?: '';
$gridQuestions = [];
if (isset($item[4]) && is_array($item[4])) {
foreach ($item[4] as $sub) {
if (!is_array($sub)) continue;
$rowTitle = '';
if (isset($sub[3]) && is_array($sub[3]) && !empty($sub[3])) {
$rowTitle = $sub[3][0];
} elseif (isset($sub[3]) && is_string($sub[3])) {
$rowTitle = $sub[3];
}
if (empty($rowTitle)) continue;
$gridQuestions[] = [
'question_text' => $rowTitle,
'question_type' => 'radio',
'is_required' => 1,
'description' => '',
'options' => null, // 5-point Rating scale
'scale_min' => 1,
'scale_max' => 5
];
}
}
if (!empty($gridQuestions)) {
$currentSection['headings'][] = [
'title' => $gridTitle,
'description' => $gridDesc,
'questions' => $gridQuestions
];
}
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)
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']) || !empty($currentSection['headings'])) {
$sections[] = $currentSection;
}
if (empty($sections)) {
$sections[] = [
'section_number' => 1,
'title' => 'ส่วนที่ 1 ข้อมูลและข้อคำถาม',
'description' => 'นำเข้าจาก Google Forms',
'category' => 'general',
'headings' => [],
'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;
// 1. Insert Headings & their questions (e.g. Grids)
if (!empty($sec['headings'])) {
foreach ($sec['headings'] as $hIdx => $h) {
$stmtH = $db->prepare("INSERT INTO survey_headings (section_id, title, description, order_num) VALUES (?, ?, ?, ?)");
$stmtH->execute([
$sectionId,
$h['title'] ?? '',
$h['description'] ?? '',
$hIdx + 1
]);
$headingId = $db->lastInsertId();
foreach ($h['questions'] as $q) {
$optionsJson = !empty($q['options']) ? json_encode($q['options'], JSON_UNESCAPED_UNICODE) : null;
$stmtQ = $db->prepare("INSERT INTO survey_questions (section_id, heading_id, question_text, question_type, is_required, order_num, options, scale_min, scale_max, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmtQ->execute([
$sectionId,
$headingId,
$q['question_text'],
$q['question_type'] ?? 'radio',
$q['is_required'] ?? 1,
$orderNum++,
$optionsJson,
$q['scale_min'] ?? 1,
$q['scale_max'] ?? 5,
$q['description'] ?? null
]);
}
}
}
// 2. Insert Loose questions
if (!empty($sec['questions'])) {
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, heading_id, question_text, question_type, is_required, order_num, options, scale_min, scale_max, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmtQ->execute([
$sectionId,
null,
$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);
}
}