Files
survey/api/export.php
T

330 lines
14 KiB
PHP

<?php
/**
* Export API
* GET ?action=pdf&survey_id=X — Export to PDF
* GET ?action=word&survey_id=X — Export to Word (DOCX)
*/
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../config/auth.php';
requireLogin();
$action = $_GET['action'] ?? '';
$surveyId = (int)($_GET['survey_id'] ?? 0);
if (!$surveyId) {
header('Content-Type: application/json; charset=utf-8');
jsonResponse(['error' => 'Missing survey_id'], 400);
}
// Check access
$db = getDB();
if (!isAdmin()) {
$stmt = $db->prepare("SELECT user_id FROM surveys WHERE id = ?");
$stmt->execute([$surveyId]);
$survey = $stmt->fetch();
if (!$survey || $survey['user_id'] != $_SESSION['user_id']) {
header('Content-Type: application/json; charset=utf-8');
jsonResponse(['error' => 'ไม่มีสิทธิ์'], 403);
}
}
// Get statistics data
$statsData = getStatsData($surveyId);
switch ($action) {
case 'pdf':
exportPDF($statsData);
break;
case 'word':
exportWord($statsData);
break;
default:
header('Content-Type: application/json; charset=utf-8');
jsonResponse(['error' => 'Invalid action'], 400);
}
function getStatsData($surveyId) {
$db = getDB();
// Survey info
$stmt = $db->prepare("SELECT s.*, u.full_name as creator_name FROM surveys s LEFT JOIN users u ON s.user_id = u.id WHERE s.id = ?");
$stmt->execute([$surveyId]);
$survey = $stmt->fetch();
// Total responses
$stmt = $db->prepare("SELECT COUNT(*) as total FROM survey_responses WHERE survey_id = ?");
$stmt->execute([$surveyId]);
$totalResponses = (int)$stmt->fetch()['total'];
// Get sections with questions & stats
$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
$hStmt = $db->prepare("SELECT * FROM survey_headings WHERE section_id = ? ORDER BY order_num");
$hStmt->execute([$section['id']]);
$headings = $hStmt->fetchAll();
$qStmt = $db->prepare("SELECT * FROM survey_questions WHERE section_id = ? ORDER BY order_num");
$qStmt->execute([$section['id']]);
$questions = $qStmt->fetchAll();
foreach ($questions as &$q) {
if ($q['question_type'] === 'radio' && empty($q['options'])) {
$aStmt = $db->prepare("
SELECT answer_value, COUNT(*) as cnt
FROM response_answers
WHERE question_id = ? AND answer_value REGEXP '^[0-9]+$'
GROUP BY answer_value
");
$aStmt->execute([$q['id']]);
$freqData = $aStmt->fetchAll();
$values = [];
$freq = [];
for ($i = 1; $i <= 5; $i++) $freq[$i] = 0;
foreach ($freqData as $fd) {
$val = (int)$fd['answer_value'];
if ($val >= 1 && $val <= 5) {
$freq[$val] = (int)$fd['cnt'];
for ($j = 0; $j < (int)$fd['cnt']; $j++) $values[] = $val;
}
}
$mean = count($values) > 0 ? array_sum($values) / count($values) : 0;
$sd = 0;
if (count($values) > 1) {
$sumSq = 0;
foreach ($values as $v) $sumSq += pow($v - $mean, 2);
$sd = sqrt($sumSq / (count($values) - 1));
}
$q['mean'] = round($mean, 2);
$q['sd'] = round($sd, 2);
$q['frequencies'] = $freq;
$q['total_answers'] = count($values);
if ($mean >= 4.51) $q['interpretation'] = 'มากที่สุด';
elseif ($mean >= 3.51) $q['interpretation'] = 'มาก';
elseif ($mean >= 2.51) $q['interpretation'] = 'ปานกลาง';
elseif ($mean >= 1.51) $q['interpretation'] = 'น้อย';
else $q['interpretation'] = 'น้อยที่สุด';
} elseif (in_array($q['question_type'], ['dropdown', 'checkbox', 'radio'])) {
$aStmt = $db->prepare("SELECT answer_value, COUNT(*) as cnt FROM response_answers WHERE question_id = ? GROUP BY answer_value ORDER BY cnt DESC");
$aStmt->execute([$q['id']]);
$q['frequencies'] = $aStmt->fetchAll();
}
if ($q['question_type'] === 'text') {
$aStmt = $db->prepare("SELECT answer_value FROM response_answers WHERE question_id = ? AND answer_value != ''");
$aStmt->execute([$q['id']]);
$q['text_responses'] = array_column($aStmt->fetchAll(), 'answer_value');
}
}
unset($q); // Break the reference to prevent overwriting last element
// Group questions by heading
$looseQuestions = [];
$headingQuestionsMap = [];
foreach ($questions as $q) {
if (!empty($q['heading_id'])) {
$headingQuestionsMap[$q['heading_id']][] = $q;
} else {
$looseQuestions[] = $q;
}
}
foreach ($headings as &$h) {
$h['questions'] = $headingQuestionsMap[$h['id']] ?? [];
}
$section['headings'] = $headings;
$section['questions'] = $looseQuestions;
}
return [
'survey' => $survey,
'total_responses' => $totalResponses,
'sections' => $sections
];
}
function generateHTML($data) {
$survey = $data['survey'];
$totalResponses = $data['total_responses'];
$sections = $data['sections'];
$html = '<!DOCTYPE html><html lang="th"><head><meta charset="UTF-8">';
$html .= '<style>
body { font-family: "TH Sarabun New", "Sarabun", sans-serif; font-size: 16px; line-height: 1.6; }
h1 { text-align: center; font-size: 20px; margin-bottom: 5px; }
h2 { font-size: 18px; margin-top: 20px; border-bottom: 1px solid #333; padding-bottom: 5px; }
table { width: 100%; border-collapse: collapse; margin: 10px 0; }
th, td { border: 1px solid #333; padding: 6px 10px; text-align: center; font-size: 14px; }
th { background-color: #f0f0f0; font-weight: bold; }
td:first-child { text-align: left; }
.info { margin: 5px 0; }
.text-response { padding: 5px 0; border-bottom: 1px dotted #ccc; }
</style></head><body>';
$html .= '<h1>รายงานผลการประเมิน</h1>';
$html .= '<h1>' . htmlspecialchars($survey['title']) . '</h1>';
$html .= '<p class="info"><strong>ผู้สร้าง:</strong> ' . htmlspecialchars($survey['creator_name'] ?? '') . '</p>';
$html .= '<p class="info"><strong>จำนวนผู้ตอบ:</strong> ' . $totalResponses . ' คน</p>';
$html .= '<p class="info"><strong>วันที่:</strong> ' . date('d/m/Y', strtotime($survey['created_at'])) . '</p>';
foreach ($sections as $section) {
$cleanSectionTitle = preg_replace('/^ส่วนที่\s*[\d๑-๙]+\s*/u', '', $section['title']);
$cleanSectionTitle = preg_replace('/^\s*[\d๑-๙]+[\.\)\s\-:\x{00A0}]*\s*/u', '', $cleanSectionTitle);
$html .= '<h2>' . htmlspecialchars($cleanSectionTitle) . '</h2>';
// Render headings and their questions
if (!empty($section['headings'])) {
foreach ($section['headings'] as $heading) {
if (!empty($heading['questions'])) {
$cleanHeadingTitle = preg_replace('/^\s*[\d๑-๙]+[\.\)\s\-:\x{00A0}]*\s*/u', '', $heading['title']);
$html .= '<h3 style="font-size:16px; margin-top:15px; color:#2563eb; border-left:3px solid #2563eb; padding-left:8px;">' . htmlspecialchars($cleanHeadingTitle) . '</h3>';
if (!empty($heading['description'])) {
$html .= '<p style="font-size:13px; color:#666; margin:0 0 8px 11px;">' . htmlspecialchars($heading['description']) . '</p>';
}
$html .= renderQuestionsHTML($heading['questions']);
}
}
}
// Render loose questions
if (!empty($section['questions'])) {
$html .= renderQuestionsHTML($section['questions']);
}
}
$html .= '</body></html>';
return $html;
}
function renderQuestionsHTML($questions) {
$html = '';
$hasRating = false;
foreach ($questions as $q) {
if ($q['question_type'] === 'radio' && empty($q['options'])) { $hasRating = true; break; }
}
if ($hasRating) {
$html .= '<table>';
$html .= '<tr><th rowspan="2">รายการประเมิน</th><th colspan="5">ระดับความคิดเห็น (ความถี่)</th><th rowspan="2">X̄</th><th rowspan="2">S.D.</th><th rowspan="2">แปลผล</th></tr>';
$html .= '<tr><th>5</th><th>4</th><th>3</th><th>2</th><th>1</th></tr>';
$totalMean = 0;
$totalSD = 0;
$ratingCount = 0;
foreach ($questions as $q) {
if ($q['question_type'] === 'radio' && empty($q['options'])) {
$cleanText = preg_replace('/^\s*[\d๑-๙]+[\.\)\s\-:\x{00A0}]*\s*/u', '', $q['question_text']);
$html .= '<tr>';
$html .= '<td>' . htmlspecialchars($cleanText) . '</td>';
for ($i = 5; $i >= 1; $i--) {
$html .= '<td>' . ($q['frequencies'][$i] ?? 0) . '</td>';
}
$html .= '<td>' . number_format($q['mean'] ?? 0, 2) . '</td>';
$html .= '<td>' . number_format($q['sd'] ?? 0, 2) . '</td>';
$html .= '<td>' . ($q['interpretation'] ?? '-') . '</td>';
$html .= '</tr>';
$totalMean += $q['mean'] ?? 0;
$totalSD += $q['sd'] ?? 0;
$ratingCount++;
}
}
if ($ratingCount > 0) {
$avgMean = $totalMean / $ratingCount;
$avgSD = $totalSD / $ratingCount;
$avgInterp = '';
if ($avgMean >= 4.51) $avgInterp = 'มากที่สุด';
elseif ($avgMean >= 3.51) $avgInterp = 'มาก';
elseif ($avgMean >= 2.51) $avgInterp = 'ปานกลาง';
elseif ($avgMean >= 1.51) $avgInterp = 'น้อย';
else $avgInterp = 'น้อยที่สุด';
$html .= '<tr style="font-weight:bold;background:#f9f9f9;">';
$html .= '<td>รวมเฉลี่ย</td><td colspan="5"></td>';
$html .= '<td>' . number_format($avgMean, 2) . '</td>';
$html .= '<td>' . number_format($avgSD, 2) . '</td>';
$html .= '<td>' . $avgInterp . '</td>';
$html .= '</tr>';
}
$html .= '</table>';
}
// Frequency tables for dropdown/checkbox/custom radio
foreach ($questions as $q) {
if (in_array($q['question_type'], ['dropdown', 'checkbox', 'radio']) && (!empty($q['options']) || $q['question_type'] !== 'radio')) {
if (!empty($q['frequencies'])) {
$cleanText = preg_replace('/^\s*[\d๑-๙]+[\.\)\s\-:\x{00A0}]*\s*/u', '', $q['question_text']);
$html .= '<p><strong>' . htmlspecialchars($cleanText) . '</strong></p>';
$html .= '<table><tr><th>ตัวเลือก</th><th>ความถี่</th><th>ร้อยละ</th></tr>';
$totalQ = array_sum(array_column($q['frequencies'], 'cnt'));
foreach ($q['frequencies'] as $f) {
$percent = $totalQ > 0 ? round(($f['cnt'] / $totalQ) * 100, 1) : 0;
$html .= '<tr><td>' . htmlspecialchars($f['answer_value']) . '</td><td>' . $f['cnt'] . '</td><td>' . $percent . '%</td></tr>';
}
$html .= '</table>';
}
}
}
// Text responses
foreach ($questions as $q) {
if ($q['question_type'] === 'text' && !empty($q['text_responses'])) {
$cleanText = preg_replace('/^\s*[\d๑-๙]+[\.\)\s\-:\x{00A0}]*\s*/u', '', $q['question_text']);
$html .= '<p><strong>' . htmlspecialchars($cleanText) . '</strong></p>';
foreach ($q['text_responses'] as $i => $text) {
$html .= '<div class="text-response">' . ($i+1) . '. ' . htmlspecialchars($text) . '</div>';
}
}
}
return $html;
}
function exportPDF($data) {
$html = generateHTML($data);
$title = $data['survey']['title'] ?? 'survey_report';
$filename = 'report_' . preg_replace('/[^a-zA-Z0-9ก-๙]/u', '_', $title) . '.pdf';
// Use simple HTML-to-PDF approach
header('Content-Type: text/html; charset=utf-8');
echo '<!DOCTYPE html><html><head><meta charset="UTF-8">';
echo '<title>' . htmlspecialchars($title) . '</title>';
echo '<style>@media print { body { -webkit-print-color-adjust: exact; } }</style>';
echo '<script>window.onload = function() { window.print(); }</script>';
echo '</head><body>';
echo $html;
echo '</body></html>';
}
function exportWord($data) {
$html = generateHTML($data);
$title = $data['survey']['title'] ?? 'survey_report';
$filename = 'report_' . preg_replace('/[^a-zA-Z0-9ก-๙]/u', '_', $title) . '.doc';
header('Content-Type: application/vnd.ms-word');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Cache-Control: max-age=0');
echo '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40">';
echo '<head><meta charset="UTF-8"><title>' . htmlspecialchars($title) . '</title></head>';
echo '<body>';
echo $html;
echo '</body></html>';
}