'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); } }