392 lines
13 KiB
PHP
392 lines
13 KiB
PHP
<?php
|
|
$sub_menu = '710600';
|
|
include_once('./_common.php');
|
|
auth_check_menu($auth, $sub_menu, "r");
|
|
|
|
// 엑셀 다운로드 처리
|
|
if (isset($_GET['sv_id']) && isset($_GET['format'])) {
|
|
$sv_id = (int)$_GET['sv_id'];
|
|
$format = $_GET['format'];
|
|
|
|
if ($format === 'excel' || $format === 'csv') {
|
|
$survey = get_survey($sv_id);
|
|
if (!$survey) {
|
|
alert('존재하지 않는 설문입니다.');
|
|
}
|
|
|
|
$export_data = get_survey_export_data($sv_id);
|
|
if (empty($export_data) || count($export_data) <= 1) { // 헤더만 있는 경우 포함
|
|
alert('내보낼 응답 데이터가 없습니다.');
|
|
}
|
|
|
|
if ($format === 'excel') {
|
|
// 💡 [수정] ZipArchive 클래스가 없는 치명적 오류를 방지하기 위해, 클래스 존재 여부를 먼저 확인합니다.
|
|
// if (!class_exists('ZipArchive')) {
|
|
// die('엑셀 파일 생성에 필요한 ZipArchive 클래스를 찾을 수 없습니다. 서버의 PHP 설정에서 "zip" 확장을 활성화해주세요.');
|
|
// }
|
|
|
|
include_once(G5_LIB_PATH . '/PHPExcel.php');
|
|
|
|
try {
|
|
// 💡 대용량 데이터 처리 시 발생할 수 있는 메모리 부족 및 시간 초과 문제를 방지합니다.
|
|
|
|
$objPHPExcel = new PHPExcel();
|
|
$objPHPExcel->setActiveSheetIndex(0)
|
|
->fromArray($export_data, null, 'A1');
|
|
|
|
// 컬럼 너비 자동 조정
|
|
$sheet = $objPHPExcel->getActiveSheet();
|
|
foreach (range('A', $sheet->getHighestDataColumn()) as $col) {
|
|
$sheet->getColumnDimension($col)->setAutoSize(true);
|
|
}
|
|
|
|
// 💡 기존에 생성된 모든 출력 버퍼를 강제로 비워서, 순수한 파일 데이터만 전송되도록 보장합니다.
|
|
while (ob_get_level()) {
|
|
ob_end_clean();
|
|
}
|
|
|
|
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
|
header('Content-Disposition: attachment; filename="survey_' . $sv_id . '_' . date('Y-m-d') . '.xlsx"');
|
|
header('Cache-Control: max-age=0');
|
|
|
|
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
|
|
$objWriter->save('php://output');
|
|
exit;
|
|
|
|
} catch (Exception $e) {
|
|
// 💡 엑셀 생성 중 오류 발생 시, 깨진 파일을 보내는 대신 명확한 오류 메시지를 출력합니다.
|
|
die('엑셀 파일 생성 중 오류가 발생했습니다. 오류: ' . htmlspecialchars($e->getMessage()));
|
|
}
|
|
} else { // CSV
|
|
// CSV 다운로드
|
|
header('Content-Type: text/csv; charset=utf-8');
|
|
header('Content-Disposition: attachment; filename="survey_' . $sv_id . '_' . date('Y-m-d') . '.csv"');
|
|
header('Cache-Control: max-age=0');
|
|
|
|
$output = fopen('php://output', 'w');
|
|
|
|
// UTF-8 BOM 추가 (엑셀에서 한글 깨짐 방지)
|
|
fprintf($output, chr(0xEF) . chr(0xBB) . chr(0xBF));
|
|
foreach ($export_data as $row) {
|
|
fputcsv($output, $row);
|
|
}
|
|
|
|
fclose($output);
|
|
exit;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
$g5['title'] = '엑셀 내보내기';
|
|
include_once(G5_ADMIN_PATH . '/admin.head.php');
|
|
|
|
// 설문 목록 가져오기
|
|
$survey_list = array();
|
|
$survey_sql = "SELECT sv_id, sv_title, sv_created_at,
|
|
(SELECT COUNT(*) FROM survey_responses WHERE sv_id = sm.sv_id AND sr_status = 'completed') as response_count
|
|
FROM survey_master sm
|
|
ORDER BY sv_created_at DESC";
|
|
$survey_result = sql_query($survey_sql);
|
|
while ($survey_row = sql_fetch_array($survey_result)) {
|
|
$survey_list[] = $survey_row;
|
|
}
|
|
?>
|
|
|
|
<style>
|
|
.export-header {
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
padding: 20px;
|
|
background: linear-gradient(135deg, #AA20FF 0%, #8A1ACC 100%);
|
|
color: white;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.export-guide {
|
|
background: #e7f3ff;
|
|
border: 1px solid #b3d9ff;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.export-guide h3 {
|
|
color: #0066cc;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.export-guide ul {
|
|
margin: 0;
|
|
padding-left: 20px;
|
|
}
|
|
|
|
.export-guide li {
|
|
margin-bottom: 8px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.survey-export-list {
|
|
background: white;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.survey-export-list table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
.survey-export-list th {
|
|
background: #fff;
|
|
padding: 15px 10px;
|
|
text-align: left;
|
|
font-weight: 600;
|
|
border-bottom: 1px solid #dee2e6;
|
|
}
|
|
|
|
.survey-export-list td {
|
|
padding: 15px 10px;
|
|
border-bottom: 1px solid #f1f3f4;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.survey-export-list tr:hover {
|
|
background: #fff;
|
|
}
|
|
|
|
.survey-title {
|
|
font-weight: 600;
|
|
color: #333;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.survey-meta {
|
|
font-size: 0.9em;
|
|
color: #666;
|
|
}
|
|
|
|
.response-count {
|
|
font-size: 1.2em;
|
|
font-weight: bold;
|
|
color: #AA20FF;
|
|
}
|
|
|
|
.export-buttons {
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
.btn-export {
|
|
padding: 8px 15px;
|
|
border: none;
|
|
border-radius: 5px;
|
|
font-size: 0.9em;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
text-decoration: none;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
}
|
|
|
|
.btn-excel {
|
|
background: #28a745;
|
|
color: white;
|
|
}
|
|
|
|
.btn-excel:hover {
|
|
background: #218838;
|
|
color: white;
|
|
}
|
|
|
|
.btn-csv {
|
|
background: #17a2b8;
|
|
color: white;
|
|
}
|
|
|
|
.btn-csv:hover {
|
|
background: #138496;
|
|
color: white;
|
|
}
|
|
|
|
.btn-export:disabled {
|
|
background: #ccc;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 80px 20px;
|
|
color: #666;
|
|
}
|
|
|
|
.empty-state i {
|
|
font-size: 4em;
|
|
margin-bottom: 20px;
|
|
display: block;
|
|
opacity: 0.3;
|
|
}
|
|
|
|
.format-info {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
gap: 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.format-card {
|
|
background: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
border-left: 4px solid #AA20FF;
|
|
}
|
|
|
|
.format-card h4 {
|
|
color: #AA20FF;
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.format-card p {
|
|
color: #666;
|
|
line-height: 1.5;
|
|
margin: 0;
|
|
}
|
|
|
|
/* 반응형 */
|
|
@media (max-width: 768px) {
|
|
.format-info {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.export-buttons {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.survey-export-list {
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
.survey-export-list th,
|
|
.survey-export-list td {
|
|
padding: 10px 5px;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div class="export-header">
|
|
<div>
|
|
<h1><i class="fa fa-download"></i> 엑셀 내보내기</h1>
|
|
<p>설문 응답 데이터를 엑셀 또는 CSV 형식으로 다운로드할 수 있습니다</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="export-guide">
|
|
<h3><i class="fa fa-info-circle"></i> 내보내기 안내</h3>
|
|
<ul>
|
|
<li><strong>엑셀 형식 (.xls)</strong>: Microsoft Excel에서 바로 열 수 있으며, 한글이 깨지지 않습니다.</li>
|
|
<li><strong>CSV 형식 (.csv)</strong>: 다양한 프로그램에서 호환되며, 데이터 분석 도구에서 사용하기 좋습니다.</li>
|
|
<li>완료된 응답만 내보내기 됩니다. (진행중이거나 중단된 응답은 제외)</li>
|
|
<li>모든 질문과 답변이 포함되며, 응답자 정보도 함께 제공됩니다.</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="format-info">
|
|
<div class="format-card">
|
|
<h4><i class="fa fa-file-excel"></i> 엑셀 형식 (XLS)</h4>
|
|
<p>Microsoft Excel에서 바로 열 수 있는 형식입니다. 한글 깨짐 없이 데이터를 확인할 수 있으며, 차트나 피벗 테이블 생성에 적합합니다.</p>
|
|
</div>
|
|
<div class="format-card">
|
|
<h4><i class="fa fa-file-csv"></i> CSV 형식</h4>
|
|
<p>범용적인 데이터 형식으로 Google Sheets, R, Python 등 다양한 분석 도구에서 사용할 수 있습니다. 대용량 데이터 처리에 적합합니다.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if (!empty($survey_list)): ?>
|
|
<div class="survey-export-list">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th width="60">ID</th>
|
|
<th>설문 제목</th>
|
|
<th width="100">응답 수</th>
|
|
<th width="120">생성일</th>
|
|
<th width="200">내보내기</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($survey_list as $survey): ?>
|
|
<tr>
|
|
<td><?php echo $survey['sv_id']; ?></td>
|
|
<td>
|
|
<div class="survey-title"><?php echo htmlspecialchars($survey['sv_title']); ?></div>
|
|
<div class="survey-meta">ID: <?php echo $survey['sv_id']; ?></div>
|
|
</td>
|
|
<td>
|
|
<span class="response-count"><?php echo number_format($survey['response_count']); ?></span>
|
|
</td>
|
|
<td>
|
|
<small><?php echo date('Y-m-d', strtotime($survey['sv_created_at'])); ?></small>
|
|
</td>
|
|
<td>
|
|
<div class="export-buttons">
|
|
<?php if ($survey['response_count'] > 0): ?>
|
|
<a href="?sv_id=<?php echo $survey['sv_id']; ?>&format=excel"
|
|
class="btn-export btn-excel">
|
|
<i class="fa fa-file-excel"></i> 엑셀
|
|
</a>
|
|
<a href="?sv_id=<?php echo $survey['sv_id']; ?>&format=csv" class="btn-export btn-csv">
|
|
<i class="fa fa-file-csv"></i> CSV
|
|
</a>
|
|
<?php else: ?>
|
|
<button class="btn-export" disabled>
|
|
<i class="fa fa-ban"></i> 응답 없음
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<?php else: ?>
|
|
<div class="empty-state">
|
|
<i class="fa fa-poll"></i>
|
|
<h3>등록된 설문이 없습니다</h3>
|
|
<p>설문을 먼저 생성해주세요.</p>
|
|
<a href="survey_form.php" style="color: #AA20FF; margin-top: 15px; display: inline-block;">
|
|
<i class="fa fa-plus"></i> 새 설문 만들기
|
|
</a>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<script>
|
|
// 다운로드 진행 상태 표시
|
|
document.querySelectorAll('.btn-export:not([disabled])').forEach(btn => {
|
|
btn.addEventListener('click', function (e) {
|
|
const originalText = this.innerHTML;
|
|
this.innerHTML = '<i class="fa fa-spinner fa-spin"></i> 준비중...';
|
|
this.style.pointerEvents = 'none';
|
|
|
|
// 3초 후 원래 상태로 복원
|
|
setTimeout(() => {
|
|
this.innerHTML = originalText;
|
|
this.style.pointerEvents = 'auto';
|
|
}, 3000);
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<?php
|
|
include_once(G5_ADMIN_PATH . '/admin.tail.php');
|
|
?>
|