'Invalid action'], 400); } function listSurveys() { $db = getDB(); if (isAdmin()) { $stmt = $db->query(" SELECT s.*, u.full_name as creator_name, (SELECT COUNT(*) FROM survey_responses WHERE survey_id = s.id) as response_count FROM surveys s LEFT JOIN users u ON s.user_id = u.id ORDER BY s.created_at DESC "); } else { $stmt = $db->prepare(" SELECT s.*, u.full_name as creator_name, (SELECT COUNT(*) FROM survey_responses WHERE survey_id = s.id) as response_count FROM surveys s LEFT JOIN users u ON s.user_id = u.id WHERE s.user_id = ? ORDER BY s.created_at DESC "); $stmt->execute([$_SESSION['user_id']]); } jsonResponse(['surveys' => $stmt->fetchAll()]); } function getSurvey() { $id = (int)($_GET['id'] ?? 0); if (!$id) jsonResponse(['error' => 'Missing ID'], 400); $db = getDB(); $stmt = $db->prepare("SELECT * FROM surveys WHERE id = ?"); $stmt->execute([$id]); $survey = $stmt->fetch(); if (!$survey) jsonResponse(['error' => 'ไม่พบแบบสอบถาม'], 404); // Check access if (!isAdmin() && $survey['user_id'] != $_SESSION['user_id']) { jsonResponse(['error' => 'ไม่มีสิทธิ์เข้าถึง'], 403); } // Get sections with questions $survey['sections'] = getSections($db, $id); jsonResponse(['survey' => $survey]); } function getByLink() { $link = $_GET['link'] ?? ''; if (empty($link)) jsonResponse(['error' => 'Missing link'], 400); $db = getDB(); $stmt = $db->prepare("SELECT * FROM surveys WHERE unique_link = ? AND status = 'active'"); $stmt->execute([$link]); $survey = $stmt->fetch(); if (!$survey) jsonResponse(['error' => 'ไม่พบแบบสอบถามหรือแบบสอบถามถูกปิด'], 404); $survey['sections'] = getSections($db, $survey['id']); // Remove sensitive data unset($survey['user_id']); jsonResponse(['survey' => $survey]); } function getSections($db, $surveyId) { $stmt = $db->prepare("SELECT * FROM survey_sections WHERE survey_id = ? ORDER BY section_number"); $stmt->execute([$surveyId]); $sections = $stmt->fetchAll(); foreach ($sections as &$section) { // Load headings for this section $hStmt = $db->prepare("SELECT * FROM survey_headings WHERE section_id = ? ORDER BY order_num"); $hStmt->execute([$section['id']]); $headings = $hStmt->fetchAll(); // Load ALL questions for this section $qStmt = $db->prepare("SELECT * FROM survey_questions WHERE section_id = ? ORDER BY order_num"); $qStmt->execute([$section['id']]); $allQuestions = $qStmt->fetchAll(); // Separate questions: those with heading_id vs those without $looseQuestions = []; $headingQuestionsMap = []; foreach ($allQuestions as &$q) { $q['is_required'] = (int)$q['is_required']; if ($q['options']) { $q['options'] = json_decode($q['options'], true); } if ($q['heading_id']) { $headingQuestionsMap[$q['heading_id']][] = $q; } else { $looseQuestions[] = $q; } } // Attach questions to their headings foreach ($headings as &$h) { $h['questions'] = $headingQuestionsMap[$h['id']] ?? []; } $section['headings'] = $headings; $section['questions'] = $looseQuestions; // questions not in any heading } return $sections; } function insertQuestion($db, $sectionId, $headingId, $q, $orderNum) { $options = isset($q['options']) ? json_encode($q['options'], JSON_UNESCAPED_UNICODE) : null; $stmt = $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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([ $sectionId, $headingId, $q['question_text'], $q['question_type'] ?? 'radio', $q['is_required'] ?? 1, $q['order_num'] ?? $orderNum, $options, $q['scale_min'] ?? 1, $q['scale_max'] ?? 5, $q['description'] ?? null ]); return $db->lastInsertId(); } function createSurvey() { $input = getInput(); $title = trim($input['title'] ?? ''); $description = trim($input['description'] ?? ''); $projectId = $input['project_id'] ?? null; if (empty($title)) { jsonResponse(['error' => 'กรุณากรอกชื่อแบบสอบถาม'], 400); } $hasCertificate = (int)($input['has_certificate'] ?? 0); $certificateTemplate = $input['certificate_template'] ?? null; $certNameY = isset($input['cert_name_y']) ? (double)$input['cert_name_y'] : 82.5; $certCodeY = isset($input['cert_code_y']) ? (double)$input['cert_code_y'] : 190.5; $db = getDB(); $uniqueLink = bin2hex(random_bytes(16)); $db->beginTransaction(); try { $stmt = $db->prepare("INSERT INTO surveys (user_id, project_id, title, description, unique_link, has_certificate, certificate_template, cert_name_y, cert_code_y) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([$_SESSION['user_id'], $projectId, $title, $description, $uniqueLink, $hasCertificate, $certificateTemplate, $certNameY, $certCodeY]); $surveyId = $db->lastInsertId(); // Create default sections with pre-defined questions based on user requirements $sections = $input['sections'] ?? [ [ 'section_number' => 1, 'title' => 'ส่วนที่ ข้อมูลทั่วไป', 'description' => 'ข้อมูลพื้นฐานของผู้ตอบ (ต้องตอบทุกข้อ)', 'questions' => [ ['question_text' => 'เพศ', 'question_type' => 'radio', 'options' => ['ชาย', 'หญิง'], 'is_required' => 1], ['question_text' => 'ช่วงอายุ', 'question_type' => 'dropdown', 'options' => ['18-25 ปี', '26-35 ปี', '36-45 ปี', '46-55 ปี', '56 ปีขึ้นไป'], 'is_required' => 1], ['question_text' => 'คณะ / หน่วยงาน', 'question_type' => 'text', 'is_required' => 1] ] ], [ 'section_number' => 2, 'title' => 'ส่วนที่ การประเมินความพึงพอใจ', 'description' => 'ประเมินระดับความพึงพอใจ (5 = มากที่สุด, 1 = น้อยที่สุด)', 'questions' => [ ['question_text' => 'ด้านเนื้อหาของการจัดโครงการ', 'question_type' => 'radio', 'is_required' => 1], ['question_text' => 'ด้านวิทยากร / ผู้บรรยาย', 'question_type' => 'radio', 'is_required' => 1], ['question_text' => 'ด้านสถานที่และความสะดวก', 'question_type' => 'radio', 'is_required' => 1] ] ], [ 'section_number' => 3, 'title' => 'ส่วนที่ ข้อเสนอแนะ', 'description' => 'ข้อเสนอแนะเพิ่มเติม', 'questions' => [ ['question_text' => 'ข้อเสนอแนะอื่นๆ', 'question_type' => 'text', 'is_required' => 0] ] ] ]; foreach ($sections as $section) { $stmt = $db->prepare("INSERT INTO survey_sections (survey_id, section_number, title, description, category) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$surveyId, $section['section_number'], $section['title'], $section['description'] ?? '', $section['category'] ?? 'rating']); $sectionId = $db->lastInsertId(); // Insert headings and their questions if (isset($section['headings'])) { foreach ($section['headings'] as $hi => $heading) { $hStmt = $db->prepare("INSERT INTO survey_headings (section_id, title, description, order_num) VALUES (?, ?, ?, ?)"); $hStmt->execute([$sectionId, $heading['title'], $heading['description'] ?? null, $heading['order_num'] ?? $hi]); $headingId = $db->lastInsertId(); if (isset($heading['questions'])) { foreach ($heading['questions'] as $i => $q) { insertQuestion($db, $sectionId, $headingId, $q, $i); } } } } // Insert loose questions (not in any heading) if (isset($section['questions'])) { foreach ($section['questions'] as $i => $q) { insertQuestion($db, $sectionId, null, $q, $i); } } } $db->commit(); jsonResponse(['success' => true, 'id' => $surveyId, 'unique_link' => $uniqueLink, 'message' => 'สร้างแบบสอบถามสำเร็จ'], 201); } catch (Exception $e) { $db->rollBack(); jsonResponse(['error' => 'เกิดข้อผิดพลาด: ' . $e->getMessage()], 500); } } function updateSurvey() { $input = getInput(); $id = (int)($input['id'] ?? 0); if (!$id) jsonResponse(['error' => 'Missing ID'], 400); $db = getDB(); // Check ownership $stmt = $db->prepare("SELECT user_id FROM surveys WHERE id = ?"); $stmt->execute([$id]); $survey = $stmt->fetch(); if (!$survey) jsonResponse(['error' => 'ไม่พบแบบสอบถาม'], 404); if (!isAdmin() && $survey['user_id'] != $_SESSION['user_id']) { jsonResponse(['error' => 'ไม่มีสิทธิ์'], 403); } $db->beginTransaction(); try { // Update survey info if (isset($input['title'])) { $hasCertificate = (int)($input['has_certificate'] ?? 0); $certificateTemplate = $input['certificate_template'] ?? null; $certNameY = isset($input['cert_name_y']) ? (double)$input['cert_name_y'] : 82.5; $certCodeY = isset($input['cert_code_y']) ? (double)$input['cert_code_y'] : 190.5; $stmt = $db->prepare("UPDATE surveys SET title = ?, description = ?, has_certificate = ?, certificate_template = ?, cert_name_y = ?, cert_code_y = ? WHERE id = ?"); $stmt->execute([$input['title'], $input['description'] ?? '', $hasCertificate, $certificateTemplate, $certNameY, $certCodeY, $id]); } // Update sections and questions if (isset($input['sections'])) { // Delete old headings first (they reference sections) $db->prepare("DELETE h FROM survey_headings h JOIN survey_sections s ON h.section_id = s.id WHERE s.survey_id = ?")->execute([$id]); // Delete old sections (cascades to questions) $db->prepare("DELETE FROM survey_sections WHERE survey_id = ?")->execute([$id]); foreach ($input['sections'] as $section) { $stmt = $db->prepare("INSERT INTO survey_sections (survey_id, section_number, title, description, category) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$id, $section['section_number'], $section['title'], $section['description'] ?? '', $section['category'] ?? 'rating']); $sectionId = $db->lastInsertId(); // Insert headings and their questions if (isset($section['headings'])) { foreach ($section['headings'] as $hi => $heading) { $hStmt = $db->prepare("INSERT INTO survey_headings (section_id, title, description, order_num) VALUES (?, ?, ?, ?)"); $hStmt->execute([$sectionId, $heading['title'], $heading['description'] ?? null, $heading['order_num'] ?? $hi]); $headingId = $db->lastInsertId(); if (isset($heading['questions'])) { foreach ($heading['questions'] as $i => $q) { insertQuestion($db, $sectionId, $headingId, $q, $i); } } } } // Insert loose questions (not in any heading) if (isset($section['questions'])) { foreach ($section['questions'] as $i => $q) { insertQuestion($db, $sectionId, null, $q, $i); } } } } $db->commit(); jsonResponse(['success' => true, 'message' => 'อัปเดตแบบสอบถามสำเร็จ']); } catch (Exception $e) { $db->rollBack(); jsonResponse(['error' => 'เกิดข้อผิดพลาด: ' . $e->getMessage()], 500); } } function deleteSurvey() { $input = getInput(); $id = (int)($input['id'] ?? 0); if (!$id) jsonResponse(['error' => 'Missing ID'], 400); $db = getDB(); $stmt = $db->prepare("SELECT user_id FROM surveys WHERE id = ?"); $stmt->execute([$id]); $survey = $stmt->fetch(); if (!$survey) jsonResponse(['error' => 'ไม่พบแบบสอบถาม'], 404); if (!isAdmin() && $survey['user_id'] != $_SESSION['user_id']) { jsonResponse(['error' => 'ไม่มีสิทธิ์'], 403); } $db->prepare("DELETE FROM surveys WHERE id = ?")->execute([$id]); jsonResponse(['success' => true, 'message' => 'ลบแบบสอบถามสำเร็จ']); } function generateLink() { $input = getInput(); $id = (int)($input['id'] ?? 0); if (!$id) jsonResponse(['error' => 'Missing ID'], 400); $db = getDB(); $newLink = bin2hex(random_bytes(16)); $stmt = $db->prepare("UPDATE surveys SET unique_link = ?, status = 'active' WHERE id = ?"); $stmt->execute([$newLink, $id]); $baseUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; $fullLink = $baseUrl . '/survey/respond.php?link=' . $newLink; jsonResponse(['success' => true, 'unique_link' => $newLink, 'full_url' => $fullLink]); } function updateStatus() { $input = getInput(); $id = (int)($input['id'] ?? 0); $status = $input['status'] ?? ''; if (!$id || !in_array($status, ['draft', 'active', 'closed'])) { jsonResponse(['error' => 'Invalid input'], 400); } $db = getDB(); $stmt = $db->prepare("UPDATE surveys SET status = ? WHERE id = ?"); $stmt->execute([$status, $id]); jsonResponse(['success' => true, 'message' => 'อัปเดตสถานะสำเร็จ']); } function duplicateSurvey() { $input = getInput(); $id = (int)($input['id'] ?? 0); if (!$id) jsonResponse(['error' => 'Missing ID'], 400); $db = getDB(); $stmt = $db->prepare("SELECT * FROM surveys WHERE id = ?"); $stmt->execute([$id]); $survey = $stmt->fetch(); if (!$survey) jsonResponse(['error' => 'ไม่พบแบบสอบถาม'], 404); $db->beginTransaction(); try { $uniqueLink = bin2hex(random_bytes(16)); $stmt = $db->prepare("INSERT INTO surveys (user_id, project_id, title, description, unique_link, status, has_certificate, certificate_template, cert_name_y, cert_code_y) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([ $_SESSION['user_id'], $survey['project_id'], "สำเนาของ " . $survey['title'], $survey['description'], $uniqueLink, 'draft', $survey['has_certificate'], $survey['certificate_template'], $survey['cert_name_y'], $survey['cert_code_y'] ]); $newSurveyId = $db->lastInsertId(); // Copy sections $stmt = $db->prepare("SELECT * FROM survey_sections WHERE survey_id = ? ORDER BY section_number"); $stmt->execute([$id]); $sections = $stmt->fetchAll(); foreach ($sections as $section) { $stmtInsert = $db->prepare("INSERT INTO survey_sections (survey_id, section_number, title, description, category) VALUES (?, ?, ?, ?, ?)"); $stmtInsert->execute([$newSurveyId, $section['section_number'], $section['title'], $section['description'], $section['category']]); $newSectionId = $db->lastInsertId(); // Copy headings $stmtH = $db->prepare("SELECT * FROM survey_headings WHERE section_id = ? ORDER BY order_num"); $stmtH->execute([$section['id']]); $headings = $stmtH->fetchAll(); $headingIdMap = []; // old heading id -> new heading id foreach ($headings as $h) { $stmtInsertH = $db->prepare("INSERT INTO survey_headings (section_id, title, description, order_num) VALUES (?, ?, ?, ?)"); $stmtInsertH->execute([$newSectionId, $h['title'], $h['description'], $h['order_num']]); $headingIdMap[$h['id']] = $db->lastInsertId(); } // Copy questions $stmtQ = $db->prepare("SELECT * FROM survey_questions WHERE section_id = ? ORDER BY order_num"); $stmtQ->execute([$section['id']]); $questions = $stmtQ->fetchAll(); foreach ($questions as $q) { $newHeadingId = $q['heading_id'] ? ($headingIdMap[$q['heading_id']] ?? null) : null; $stmtInsertQ = $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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmtInsertQ->execute([ $newSectionId, $newHeadingId, $q['question_text'], $q['question_type'], $q['is_required'], $q['order_num'], $q['options'], $q['scale_min'], $q['scale_max'], $q['description'] ]); } } $db->commit(); jsonResponse(['success' => true, 'id' => $newSurveyId, 'message' => 'คัดลอกแบบสอบถามสำเร็จ']); } catch (Exception $e) { $db->rollBack(); jsonResponse(['error' => 'เกิดข้อผิดพลาด: ' . $e->getMessage()], 500); } } function uploadTemplate() { if (!isset($_FILES['template_image'])) { jsonResponse(['error' => 'ไม่พบไฟล์ที่อัปโหลด'], 400); } $file = $_FILES['template_image']; if ($file['error'] !== UPLOAD_ERR_OK) { jsonResponse(['error' => 'การอัปโหลดไฟล์ล้มเหลว: รหัสข้อผิดพลาด ' . $file['error']], 400); } // ตรวจสอบขนาดไฟล์ (สูงสุด 5MB) if ($file['size'] > 5 * 1024 * 1024) { jsonResponse(['error' => 'ขนาดไฟล์รูปภาพต้องไม่เกิน 5MB'], 400); } // ตรวจสอบนามสกุล/ประเภทไฟล์ (ต้องเป็น PNG หรือ JPEG เท่านั้น) $imageInfo = getimagesize($file['tmp_name']); if ($imageInfo === false) { jsonResponse(['error' => 'ไฟล์ที่อัปโหลดไม่ใช่รูปภาพที่ถูกต้อง'], 400); } $mimeType = $imageInfo['mime']; $allowedMimeTypes = ['image/png', 'image/jpeg', 'image/jpg']; if (!in_array($mimeType, $allowedMimeTypes)) { jsonResponse(['error' => 'อนุญาตให้อัปโหลดเฉพาะไฟล์รูปภาพ PNG หรือ JPG/JPEG เท่านั้น'], 400); } // สร้างโฟลเดอร์สำหรับเก็บไฟล์รูปภาพ (ถ้ายังไม่มี) $uploadDir = __DIR__ . '/../uploads/templates'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0777, true); } chmod($uploadDir, 0777); // สร้างชื่อไฟล์ใหม่เพื่อป้องกันไฟล์ซ้ำและแฮกเกอร์ $ext = ($mimeType === 'image/png') ? 'png' : 'jpg'; $fileName = 'tpl_' . time() . '_' . bin2hex(random_bytes(8)) . '.' . $ext; $destPath = $uploadDir . '/' . $fileName; if (move_uploaded_file($file['tmp_name'], $destPath)) { chmod($destPath, 0666); $relativePath = 'uploads/templates/' . $fileName; jsonResponse(['success' => true, 'template_path' => $relativePath, 'message' => 'อัปโหลดเทมเพลตสำเร็จ']); } else { jsonResponse(['error' => 'ไม่สามารถย้ายไฟล์ไปยังโฟลเดอร์ปลายทางได้'], 500); } }