first commit 2

This commit is contained in:
hmw1001
2026-06-11 18:47:38 +09:00
parent c768729ce6
commit 6f534e33a6
11095 changed files with 1595758 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
<?php
define('G5_IS_ADMIN', true);
include_once('../../common.php');
include_once(G5_ADMIN_PATH . '/admin.lib.php');
$g5['contact_inquiry_table'] = G5_TABLE_PREFIX . 'contact_inquiry';
?>
@@ -0,0 +1,12 @@
<?php
if (!defined('_GNUBOARD_')) exit;
// 810번대 메뉴 (상담문의관리)
if (!isset($menu['menu810'])) $menu['menu810'] = array();
$menu['menu810'] = array_merge($menu['menu810'], array(
array('810000', '상담문의관리', G5_ADMIN_URL.'/contact_inquiry/list.php', 'contact_inquiry_main', 'fa-comments'),
array('810100', '상담문의내역', G5_ADMIN_URL.'/contact_inquiry/list.php', 'contact_inquiry_list'),
array('810900', '솔루션 설치', G5_ADMIN_URL.'/contact_inquiry/install.php', 'contact_inquiry_install'),
));
?>
@@ -0,0 +1,12 @@
<?php
if (!defined('_GNUBOARD_')) exit;
// 💡 [개선] 다른 모듈과의 호환성을 위해 배열을 덮어쓰지 않고 추가/병합합니다.
if (!isset($menu['menu850'])) $menu['menu850'] = array();
$menu['menu850'] = array_merge($menu['menu850'], array(
array('850700', '상담문의관리', G5_ADMIN_URL.'/contact_inquiry/list.php', 'contact_inquiry_main', 'fa-comments'),
array('850710', '상담문의내역', G5_ADMIN_URL.'/contact_inquiry/list.php', 'contact_inquiry_list'),
array('850790', '솔루션 설치', G5_ADMIN_URL.'/contact_inquiry/install.php', 'contact_inquiry_install'),
));
?>
+91
View File
@@ -0,0 +1,91 @@
<?php
// 💡 [수정] 관리자 인증을 건너뛰기 위해 `_common.php` 대신 `common.php`를 직접 포함합니다.
// 이렇게 하면 일반 사용자가 로그인 없이도 이 파일에 접근하여 문의를 저장할 수 있습니다.
include_once(__DIR__ . '/_common.php');
// `_common.php`에 정의된 테이블 상수를 여기서 직접 정의합니다.
$g5['contact_inquiry_table'] = G5_TABLE_PREFIX . 'contact_inquiry';
$response = [
'success' => false,
'message' => '알 수 없는 오류가 발생했습니다.'
];
try {
// POST 데이터가 없으면 오류 처리
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
throw new Exception('잘못된 요청 방식입니다.');
}
$contact_subject = isset($_POST['contact_subject']) ? trim($_POST['contact_subject']) : '';
$contact_name = isset($_POST['contact_name']) ? trim($_POST['contact_name']) : '';
$contact_hp = isset($_POST['contact_hp']) ? trim($_POST['contact_hp']) : '';
$contact_zip = isset($_POST['contact_zip']) ? trim($_POST['contact_zip']) : '';
$contact_addr1 = isset($_POST['contact_addr1']) ? trim($_POST['contact_addr1']) : '';
$contact_addr2 = isset($_POST['contact_addr2']) ? trim($_POST['contact_addr2']) : '';
$contact_message = isset($_POST['contact_message']) ? trim($_POST['contact_message']) : '';
if (empty($contact_name) || empty($contact_hp) || empty($contact_message)) {
throw new Exception('필수 입력 항목이 누락되었습니다.');
}
// SQL Injection 방지를 위해 escaping
$contact_subject = sql_real_escape_string($contact_subject);
$contact_name = sql_real_escape_string($contact_name);
$contact_hp = sql_real_escape_string($contact_hp);
$contact_zip = sql_real_escape_string($contact_zip);
$contact_addr1 = sql_real_escape_string($contact_addr1);
$contact_addr2 = sql_real_escape_string($contact_addr2);
$contact_message = sql_real_escape_string($contact_message);
$sql = " INSERT INTO {$g5['contact_inquiry_table']}
SET contact_subject = '{$contact_subject}',
contact_name = '{$contact_name}',
contact_hp = '{$contact_hp}',
contact_zip = '{$contact_zip}',
contact_addr1 = '{$contact_addr1}',
contact_addr2 = '{$contact_addr2}',
contact_message = '{$contact_message}',
created_at = '" . G5_TIME_YMDHIS . "',
status = 'new' ";
// 테이블 존재 여부 확인 (테이블이 없어서 에러나는 경우 방지)
$table_check = sql_query(" DESCRIBE {$g5['contact_inquiry_table']} ", false);
if (!$table_check) {
// 테이블이 없으면 자동 생성 시도
$create_sql = "
CREATE TABLE IF NOT EXISTS `{$g5['contact_inquiry_table']}` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`contact_subject` varchar(255) NOT NULL DEFAULT '' COMMENT '문의 항목 (주거형태 등)',
`contact_name` varchar(255) NOT NULL DEFAULT '' COMMENT '이름',
`contact_hp` varchar(255) NOT NULL DEFAULT '' COMMENT '연락처',
`contact_zip` varchar(10) NOT NULL DEFAULT '' COMMENT '우편번호',
`contact_addr1` varchar(255) NOT NULL DEFAULT '' COMMENT '기본 주소',
`contact_addr2` varchar(255) NOT NULL DEFAULT '' COMMENT '상세 주소',
`contact_message` text NOT NULL COMMENT '문의 내용',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '작성일',
`status` varchar(20) NOT NULL DEFAULT 'new' COMMENT '상태 (new, read, done)',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='상담 문의 내역';
";
sql_query($create_sql);
}
if (sql_query($sql)) {
$response['success'] = true;
$response['message'] = '상담 신청이 성공적으로 저장되었습니다.';
} else {
throw new Exception('데이터베이스 저장 중 오류가 발생했습니다.');
}
} catch (Exception $e) {
$response['message'] = $e->getMessage();
}
// 버퍼 비우기 (혹시 모를 공백이나 경고 메시지 제거)
ob_clean();
header('Content-Type: application/json');
echo json_encode($response);
exit;
?>
+154
View File
@@ -0,0 +1,154 @@
/**
* 파일명: contact-form-handler.js
* 설명: 홈페이지 메인의 상담 신청 폼을 처리하고 팝업을 제어하는 스크립트
*/
document.addEventListener('DOMContentLoaded', function() {
// 모달 요소 선택 (contact.skin.php의 구조에 맞춤)
const modal = document.getElementById('contact-modal');
// 모달이 없으면 실행 중단
if (!modal) return;
const closeBtn = modal.querySelector('.modal-close');
// modal 자체가 overlay 역할을 하므로 overlay 변수는 modal과 동일하거나 별도 배경 요소일 수 있음
// contact.skin.php 구조상 id="contact-modal"이 overlay 역할을 함
const overlay = modal;
const contactForm = modal.querySelector('form');
const formMessages = modal.querySelector('.form-message-area');
const submitButton = contactForm ? contactForm.querySelector('button[type="submit"]') : null;
// 모달 열기 함수
const openModal = (e) => {
if (e) e.preventDefault();
modal.classList.add('active'); // CSS에서 .active 클래스로 제어한다고 가정
document.body.style.overflow = 'hidden';
};
// 모달 닫기 함수
const closeModal = () => {
modal.classList.remove('active');
document.body.style.overflow = '';
};
// 1. 모달 열기 이벤트 위임 (어디서든 .open-contact-modal 클래스 클릭 시 열림)
document.addEventListener('click', function(e) {
const targetBtn = e.target.matches('.open-contact-modal') ? e.target : e.target.closest('.open-contact-modal');
if (targetBtn) {
openModal(e);
}
});
// 2. 모달 닫기 이벤트
if (closeBtn) {
closeBtn.addEventListener('click', closeModal);
}
// 배경 클릭 시 닫기
if (overlay) {
overlay.addEventListener('click', function(e) {
if (e.target === overlay) {
closeModal();
}
});
}
// ESC 키 누르면 닫기
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modal.classList.contains('active')) {
closeModal();
}
});
// 3. 폼 제출 처리
if (contactForm && submitButton) {
contactForm.addEventListener('submit', function(e) {
e.preventDefault(); // 기본 폼 전송 막기
const originalButtonText = submitButton.textContent;
submitButton.disabled = true;
submitButton.textContent = '전송 중...';
if (formMessages) {
formMessages.style.display = 'none';
formMessages.className = 'form-message-area'; // 초기화
formMessages.innerHTML = '';
}
const formData = new FormData(contactForm);
// 💡 [DB 저장] AJAX 요청으로 먼저 데이터를 서버에 저장
// GnuBoard의 g5_url 변수를 사용하여 AJAX 요청 URL을 생성합니다.
const save_url = (typeof g5_url !== 'undefined' ? g5_url : '') + '/adm/contact_inquiry/ajax_save_inquiry.php';
fetch(save_url, {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) {
throw new Error('서버와의 통신에 실패했습니다.');
}
return response.json();
})
.then(data => {
if (data.success) {
// DB 저장 성공 시 메일 발송 진행
const variables = {
contact_subject: formData.get('contact_subject'),
contact_name: formData.get('contact_name'),
contact_hp: formData.get('contact_hp'),
contact_email: formData.get('contact_email'),
contact_message: formData.get('contact_message').replace(/\n/g, '<br>')
};
// universalMailer 객체 확인 및 메일 발송
if (window.universalMailer && typeof window.universalMailer.send === 'function') {
window.universalMailer.send({
template_code: 'contact_inquiry', // 관리자에서 생성할 템플릿 코드
to_email : variables.contact_email,
// [추가] 참조 이메일 설정
// 'ADMIN_EMAIL' 키워드를 사용하면 서버(ajax_universal_send.php)에서
// 실제 관리자 이메일 주소(config.php의 cf_admin_email)로 자동 치환합니다.
cc_email: ['ADMIN_EMAIL'],
// bcc_email: ['msbfox@naver.com'],
variables: variables,
onSuccess: function(response) {
alert(response.message || '상담 신청이 성공적으로 접수되었습니다.');
contactForm.reset();
closeModal();
},
onError: function(errorMessage) {
if (formMessages) {
formMessages.innerHTML = `<div class="message error">${errorMessage || '오류가 발생했습니다.'}</div>`;
formMessages.style.display = 'block';
} else {
alert(errorMessage || '오류가 발생했습니다.');
}
},
onComplete: function() {
submitButton.disabled = false;
submitButton.textContent = originalButtonText;
}
});
} else {
// 메일 모듈이 없어도 DB 저장은 되었으므로 성공 처리 (선택사항)
alert('상담 신청이 접수되었습니다. (메일 발송 실패)');
contactForm.reset();
closeModal();
submitButton.disabled = false;
submitButton.textContent = originalButtonText;
}
} else {
throw new Error(data.message || '상담 신청 저장 중 오류가 발생했습니다.');
}
})
.catch(error => {
console.error('Error:', error);
alert(error.message || '오류가 발생했습니다.');
submitButton.disabled = false;
submitButton.textContent = originalButtonText;
});
});
}
});
+10
View File
@@ -0,0 +1,10 @@
<?php
include_once('./_common.php');
$id = $_GET['id'];
if (!$id) alert('잘못된 접근입니다.');
sql_query(" delete from {$g5['contact_inquiry_table']} where id = '{$id}' ");
goto_url('./list.php');
?>
+171
View File
@@ -0,0 +1,171 @@
<?php
$sub_menu = '810900';
include_once('./_common.php');
include_once(__DIR__ . '/lib/SchemaManager.class.php');
if (!$is_admin) {
alert('관리자만 접근할 수 있습니다.');
}
/**
* SQL 파일에서 테이블 이름을 추출하는 함수
*/
function get_tables_from_sql_file($filepath) {
$tables = [];
if (!file_exists($filepath)) return $tables;
$lines = file($filepath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (preg_match('/CREATE TABLE(?: IF NOT EXISTS)? `([^`]+)`/i', $line, $matches)) {
$tables[] = $matches[1];
}
}
return $tables;
}
$g5['title'] = '상담 문의 시스템 설치';
include_once(G5_ADMIN_PATH . '/admin.head.php');
$install_result = null;
$delete_result = null;
$action = $_POST['action'] ?? '';
$tables_to_check = get_tables_from_sql_file(__DIR__ . '/install.sql');
if ($action === 'install') {
check_admin_token();
try {
$sql_file = __DIR__ . '/install.sql';
$schemaManager = new SchemaManager($sql_file);
$schemaManager->execute();
$db_results = $schemaManager->get_results();
$menu_msg = create_admin_menu_file();
$install_result = ['db' => $db_results, 'menu' => $menu_msg];
} catch (Exception $e) {
$install_result['errors'][] = '설치 중 심각한 오류 발생: ' . $e->getMessage();
}
} else if ($action === 'delete') {
check_admin_token();
$delete_result = ['tables' => [], 'menu' => ''];
$tables_to_delete = $tables_to_check;
foreach ($tables_to_delete as $table) {
sql_query("DROP TABLE IF EXISTS `{$table}`", false);
$delete_result['tables'][] = $table;
}
// 💡 [수정] 810번 메뉴 파일 삭제
$menu_file = G5_ADMIN_PATH . '/admin.menu810.contact.php';
if (file_exists($menu_file)) {
if (@unlink($menu_file)) {
$delete_result['menu'] = '메뉴 파일 삭제 성공';
} else {
$delete_result['menu'] = '메뉴 파일 삭제 실패 (권한 확인 필요)';
}
}
}
function create_admin_menu_file() {
// 💡 [수정] 810번 메뉴 파일 생성
$source_file = __DIR__ . '/admin.menu810.contact.php';
$target_file = G5_ADMIN_PATH . '/admin.menu810.contact.php';
if (!file_exists($source_file)) return "실패 (메뉴 원본 파일 없음)";
if (file_exists($target_file)) return "성공 (이미 존재함)";
if (@copy($source_file, $target_file)) return "성공";
return "실패 (파일 복사 오류)";
}
$existing_tables = [];
foreach ($tables_to_check as $table) {
if (sql_query("SHOW TABLES LIKE '$table'", false) && sql_num_rows(sql_query("SHOW TABLES LIKE '$table'", false)) > 0) {
$existing_tables[] = $table;
}
}
$is_installed = count($existing_tables) == count($tables_to_check);
?>
<style>
.install-container { max-width: 800px; margin: 20px auto; padding: 20px; background: #fff; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.install-header { text-align: center; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 2px solid #007bff; }
.install-header h1 { color: #007bff; margin-bottom: 10px; }
.status-table { width: 100%; border-collapse: collapse; margin: 20px 0; }
.status-table th, .status-table td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
.status-table th { background-color: #f8f9fa; font-weight: bold; }
.status-ok { color: #28a745; font-weight: bold; }
.status-missing { color: #dc3545; font-weight: bold; }
.install-btn { display: block; width: 200px; margin: 30px auto; padding: 15px 30px; background: #007bff; color: white; text-align: center; text-decoration: none; border-radius: 5px; font-size: 16px; font-weight: bold; border: none; cursor: pointer; transition: background-color 0.3s; }
.install-btn:hover { background: #0056b3; color: white; }
.install-btn:disabled { background: #ccc; cursor: not-allowed; }
.alert { padding: 15px; margin: 20px 0; border-radius: 5px; }
.alert-success { background-color: #d4edda; border: 1px solid #c3e6cb; color: #155724; }
.alert-info { background-color: #d1ecf1; border: 1px solid #bee5eb; color: #0c5460; }
.alert-danger { background-color: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; }
.btn-secondary { background: #6c757d; color: white; border-color: #6c757d; padding: 5px 10px; border-radius: 4px; text-decoration: none; }
.btn-secondary:hover { background: #5a6268; }
.btn-danger { background: #dc3545; color: white; border: none; padding: 10px 15px; border-radius: 4px; cursor: pointer; }
.btn-danger:hover { background: #c82333; }
.button-group { display: flex; justify-content: center; align-items: center; gap: 10px; }
</style>
<div class="install-container">
<div class="install-header">
<h1><i class="fa fa-comments"></i> 상담 문의 시스템</h1>
<p>홈페이지의 문의 양식을 데이터베이스에 저장하고 관리합니다.</p>
</div>
<?php if ($install_result): ?>
<div class="alert alert-success"><h4><i class="fa fa-check-circle"></i> 설치 작업 완료</h4>
<p>데이터베이스 및 기본 설정 설치가 완료되었습니다.</p>
<p><?php echo 'menu : '.$install_result['menu']; ?></p>
<p><a href="./list.php" class="btn btn-primary">상담 문의 내역으로 이동</a></p></div>
<?php elseif ($delete_result): ?>
<div class="alert alert-danger"><h4><i class="fa fa-trash"></i> 삭제 작업 완료</h4><p>솔루션 관련 데이터와 파일이 삭제되었습니다.</p><ul><?php foreach($delete_result['tables'] as $tbl) echo "<li>{$tbl} 테이블 삭제됨</li>"; ?><li><?php echo $delete_result['menu']; ?></li></ul></div>
<?php elseif ($is_installed): ?>
<div class="alert alert-success"><h4><i class="fa fa-check-circle"></i> 설치 완료</h4><p>상담 문의 시스템이 이미 설치되어 있습니다.</p><p><a href="./list.php" class="btn btn-primary">상담 문의 내역으로 이동</a></p></div>
<?php else: ?>
<div class="alert alert-info"><h4><i class="fa fa-info-circle"></i> 설치 필요</h4><p>상담 문의 시스템을 사용하기 위해 설치가 필요합니다.</p></div>
<?php endif; ?>
<h3><i class="fa fa-database"></i> 설치 상태</h3>
<table class="status-table">
<thead><tr><th>테이블명</th><th>설명</th><th>상태</th></tr></thead>
<tbody>
<?php foreach ($tables_to_check as $table): ?>
<tr>
<td><code><?php echo $table; ?></code></td>
<td>상담 문의 내역 저장 테이블</td>
<td>
<?php if (in_array($table, $existing_tables)): ?>
<span class="status-ok"><i class="fa fa-check"></i> 설치됨</span>
<?php else: ?>
<span class="status-missing"><i class="fa fa-times"></i> 미설치</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php if (!$is_installed): ?>
<form method="post" onsubmit="return confirm('솔루션을 설치하시겠습니까?');">
<input type="hidden" name="action" value="install">
<input type="hidden" name="token" value="<?php echo get_token(); ?>">
<button type="submit" class="install-btn"><i class="fa fa-download"></i> 솔루션 설치하기</button>
</form>
<?php endif; ?>
<?php if ($is_installed && !$install_result && !$delete_result): ?>
<div class="button-group" style="text-align: center; margin-top: 20px;">
<form method="post" onsubmit="return confirm('기존 데이터는 유지되며, 변경된 DB 구조만 업데이트 됩니다. 진행하시겠습니까?');">
<input type="hidden" name="action" value="install">
<input type="hidden" name="token" value="<?php echo get_token(); ?>">
<button type="submit" class="btn btn-secondary"><i class="fa fa-sync"></i> 재설치 (업데이트)</button>
</form>
<form method="post" onsubmit="return confirm('정말로 솔루션을 삭제하시겠습니까? 모든 관련 데이터와 파일이 영구적으로 삭제됩니다.');">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="token" value="<?php echo get_token(); ?>">
<button type="submit" class="btn-danger"><i class="fa fa-trash"></i> 솔루션 삭제하기</button>
</form>
</div>
<?php endif; ?>
</div>
<?php
include_once(G5_ADMIN_PATH . '/admin.tail.php');
?>
+13
View File
@@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS `g5_contact_inquiry` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`contact_subject` varchar(255) NOT NULL DEFAULT '' COMMENT '문의 항목 (주거형태 등)',
`contact_name` varchar(255) NOT NULL DEFAULT '' COMMENT '이름',
`contact_hp` varchar(255) NOT NULL DEFAULT '' COMMENT '연락처',
`contact_zip` varchar(10) NOT NULL DEFAULT '' COMMENT '우편번호',
`contact_addr1` varchar(255) NOT NULL DEFAULT '' COMMENT '기본 주소',
`contact_addr2` varchar(255) NOT NULL DEFAULT '' COMMENT '상세 주소',
`contact_message` text NOT NULL COMMENT '문의 내용',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '작성일',
`status` varchar(20) NOT NULL DEFAULT 'new' COMMENT '상태 (new, read, done)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='상담 문의 내역';
@@ -0,0 +1,206 @@
<?php
if (!defined('_GNUBOARD_')) exit;
/**
* SQL 파일을 기반으로 데이터베이스 스키마를 관리(생성/업데이트)하는 범용 클래스
*/
class SchemaManager
{
private $sql_file_path;
private $results;
private $conn; // DB 연결 객체를 저장할 변수
/**
* 생성자
* @param string $sql_file_path install.sql 파일의 절대 경로
*/
public function __construct($sql_file_path)
{
global $g5; // 그누보드 DB 연결 객체에 접근하기 위해 global 선언
$this->conn = $g5['connect_db']; // DB 연결 객체를 저장
if (!file_exists($sql_file_path)) {
throw new Exception($sql_file_path . ' 파일을 찾을 수 없습니다.');
}
$this->sql_file_path = $sql_file_path;
$this->results = [
'created' => [],
'existing' => [],
'updated' => [],
'failed' => [],
'errors' => [],
];
}
/**
* 스키마 설치/업데이트를 실행합니다.
*/
public function execute()
{
$sql_statements = $this->parse_sql_file();
foreach ($sql_statements as $stmt) {
// CREATE TABLE 문인지 확인
if (preg_match('/^CREATE\s+TABLE/i', $stmt)) {
$schema = $this->parse_create_table_sql($stmt);
if ($schema && !empty($schema['name'])) {
$this->process_table_schema($stmt, $schema);
}
} else {
// CREATE TABLE 문이 아닌 다른 SQL 문 (e.g. INSERT, UPDATE)
mysqli_query($this->conn, $stmt);
}
}
}
/**
* 처리 결과를 반환합니다.
* @return array
*/
public function get_results()
{
return $this->results;
}
/**
* 테이블 스키마를 처리합니다. (생성 또는 업데이트)
* @param string $create_sql 전체 CREATE TABLE 구문
* @param array $schema 파싱된 스키마 정보
*/
private function process_table_schema($create_sql, $schema)
{
$table_name = $schema['name'];
if ($this->table_exists($table_name)) {
// 테이블이 존재하면, 컬럼 비교 및 추가/수정
$this->results['existing'][] = $table_name;
$this->update_table_columns($table_name, $schema['columns']);
} else {
// 테이블이 존재하지 않으면, 새로 생성
if (mysqli_query($this->conn, $create_sql)) {
$this->results['created'][] = $table_name;
} else {
$this->results['failed'][] = $table_name;
$this->results['errors'][] = "<strong>{$table_name} 테이블 생성 실패</strong>: " . mysqli_error($this->conn);
}
}
}
/**
* 테이블의 컬럼 구조를 업데이트합니다.
* @param string $table_name
* @param array $target_columns .sql 파일에 정의된 컬럼 목록
*/
private function update_table_columns($table_name, $target_columns)
{
$current_columns = $this->get_current_columns($table_name);
$added_columns_in_table = [];
foreach ($target_columns as $col_name => $col_definition) {
// 현재 테이블에 해당 컬럼이 없으면 추가
if (!isset($current_columns[$col_name])) {
$alter_sql = "ALTER TABLE `{$table_name}` ADD COLUMN `{$col_name}` {$col_definition}";
if (mysqli_query($this->conn, $alter_sql)) {
$added_columns_in_table[] = $col_name;
} else {
$this->results['failed'][] = "{$table_name} (컬럼: {$col_name})";
$this->results['errors'][] = "<strong>{$table_name} 테이블에 '{$col_name}' 컬럼 추가 실패</strong>: " . mysqli_error($this->conn);
}
} else {
// 💡 [핵심 수정] 컬럼이 이미 존재하면, 코멘트 등을 업데이트하기 위해 MODIFY 실행
$alter_sql = "ALTER TABLE `{$table_name}` MODIFY COLUMN `{$col_name}` {$col_definition}";
if (!mysqli_query($this->conn, $alter_sql)) {
// MODIFY 실패 시 에러 기록
$this->results['failed'][] = "{$table_name} (컬럼: {$col_name})";
$this->results['errors'][] = "<strong>{$table_name} 테이블의 '{$col_name}' 컬럼 수정 실패</strong>: " . mysqli_error($this->conn);
}
}
}
if (!empty($added_columns_in_table)) {
$this->results['updated'][$table_name] = $added_columns_in_table;
}
}
/**
* SQL 파일을 읽고 각 구문으로 분리합니다.
* @return array
*/
private function parse_sql_file()
{
$sql = file_get_contents($this->sql_file_path);
// 주석 제거 (SQL 주석 '--' 와 C-style '/* ... */' 주석)
$sql = preg_replace('/--.*/', '', $sql);
$sql = preg_replace('!/\*.*?\*/!s', '', $sql);
$sql = trim($sql);
// 세미콜론(;)을 기준으로 쿼리 분리
return array_filter(array_map('trim', explode(';', $sql)));
}
/**
* 테이블 존재 여부를 확인합니다.
* @param string $table_name
* @return bool
*/
private function table_exists($table_name)
{
$res = mysqli_query($this->conn, "SHOW TABLES LIKE '{$table_name}'");
return mysqli_num_rows($res) > 0;
}
/**
* 현재 DB에 있는 테이블의 컬럼 목록을 가져옵니다.
* @param string $table_name
* @return array
*/
private function get_current_columns($table_name)
{
$res = mysqli_query($this->conn, "SHOW COLUMNS FROM `{$table_name}`");
$columns = [];
while ($row = mysqli_fetch_array($res)) {
$columns[$row['Field']] = true;
}
return $columns;
}
/**
* CREATE TABLE SQL 구문에서 테이블명과 컬럼 정의를 파싱합니다.
* @param string $query CREATE TABLE 구문
* @return array|null
*/
private function parse_create_table_sql($query)
{
$table_name = '';
if (preg_match('/CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?\s+`?(\w+)`?/i', $query, $matches)) {
$table_name = $matches[1];
} else {
return null;
}
// 괄호 안의 내용만 추출
$start = strpos($query, '(');
$end = strrpos($query, ')');
if ($start === false || $end === false) {
return ['name' => $table_name, 'columns' => []];
}
$content = substr($query, $start + 1, $end - $start - 1);
// 줄 단위로 분리
$lines = explode("\n", $content);
$columns = [];
foreach ($lines as $line) {
$line = trim($line, " \t\n\r\0\x0B,"); // 양쪽 공백과 마지막 쉼표 제거
// 컬럼 정의 라인인지 확인 (첫 단어가 `column_name` 형태)
if (preg_match('/^`(\w+)`\s+(.*)/i', $line, $match)) {
$col_name = $match[1];
$col_definition = $match[2];
$columns[$col_name] = $col_definition;
}
}
return ['name' => $table_name, 'columns' => $columns];
}
}
+133
View File
@@ -0,0 +1,133 @@
<?php
$sub_menu = "810100";
include_once('./_common.php');
auth_check_menu($auth, $sub_menu, 'r');
$g5['title'] = '상담 문의 내역';
include_once(G5_ADMIN_PATH.'/admin.head.php');
$sql_common = " FROM {$g5['contact_inquiry_table']} ";
$sql_search = " WHERE (1) ";
if ($stx) {
$sql_search .= " AND ( ";
switch ($sfl) {
case "contact_name" :
case "contact_hp" :
case "contact_subject" :
$sql_search .= " ({$sfl} like '%{$stx}%') ";
break;
default :
$sql_search .= " ({$sfl} like '%{$stx}%') ";
break;
}
$sql_search .= " ) ";
}
if (!$sst) {
$sst = "id";
$sod = "desc";
}
$sql_order = " order by {$sst} {$sod} ";
$sql = " select count(*) as cnt {$sql_common} {$sql_search} ";
$row = sql_fetch($sql);
$total_count = $row['cnt'];
$rows = $config['cf_page_rows'];
$total_page = ceil($total_count / $rows); // 전체 페이지 계산
if ($page < 1) { $page = 1; } // 페이지가 없으면 첫 페이지 (1 페이지)
$from_record = ($page - 1) * $rows; // 시작 열을 구함
$sql = " select * {$sql_common} {$sql_search} {$sql_order} limit {$from_record}, {$rows} ";
$result = sql_query($sql);
$listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목록</a>';
?>
<div class="local_ov01 local_ov">
<?php echo $listall; ?>
<span class="btn_ov01"><span class="ov_txt">전체 </span><span class="ov_num"> <?php echo number_format($total_count); ?>건</span></span>
</div>
<form name="fsearch" id="fsearch" class="local_sch01 local_sch" method="get">
<div class="sch_last">
<strong>검색</strong>
<input type="hidden" name="page" value="<?php echo $page; ?>">
<select name="sfl" id="sfl">
<option value="contact_name"<?php echo get_selected($_GET['sfl'], "contact_name"); ?>>이름</option>
<option value="contact_hp"<?php echo get_selected($_GET['sfl'], "contact_hp"); ?>>연락처</option>
<option value="contact_subject"<?php echo get_selected($_GET['sfl'], "contact_subject"); ?>>주거형태</option>
</select>
<label for="stx" class="sound_only">검색어<strong class="sound_only"> 필수</strong></label>
<input type="text" name="stx" value="<?php echo $stx; ?>" id="stx" required class="frm_input">
<button type="submit" class="btn_submit">검색</button>
</div>
</form>
<form name="fcontactlist" id="fcontactlist" method="post" action="./contact_list_update.php" onsubmit="return fcontactlist_submit(this);">
<input type="hidden" name="sst" value="<?php echo $sst; ?>">
<input type="hidden" name="sod" value="<?php echo $sod; ?>">
<input type="hidden" name="sfl" value="<?php echo $sfl; ?>">
<input type="hidden" name="stx" value="<?php echo $stx; ?>">
<input type="hidden" name="page" value="<?php echo $page; ?>">
<input type="hidden" name="token" value="<?php echo $token; ?>">
<div class="tbl_head01 tbl_wrap">
<table>
<caption><?php echo $g5['title']; ?> 목록</caption>
<thead>
<tr>
<th scope="col">번호</th>
<th scope="col">주거형태</th>
<th scope="col">이름</th>
<th scope="col">연락처</th>
<th scope="col">주소</th>
<th scope="col">문의내용</th>
<th scope="col">등록일</th>
<th scope="col">관리</th>
</tr>
</thead>
<tbody>
<?php
for ($i=0; $row=sql_fetch_array($result); $i++) {
$bg = 'bg'.($i%2);
?>
<tr class="<?php echo $bg; ?>">
<td class="td_num"><?php echo $row['id']; ?></td>
<td class="td_category"><?php echo $row['contact_subject']; ?></td>
<td class="td_name"><?php echo $row['contact_name']; ?></td>
<td class="td_tel"><?php echo $row['contact_hp']; ?></td>
<td class="td_left">
<?php
echo "(" . $row['contact_zip'] . ") ";
echo $row['contact_addr1'] . " " . $row['contact_addr2'];
?>
</td>
<td class="td_left"><?php echo conv_content($row['contact_message'], 0); ?></td>
<td class="td_datetime"><?php echo $row['created_at']; ?></td>
<td class="td_mng">
<a href="./contact_form.php?w=u&amp;id=<?php echo $row['id']; ?>&amp;<?php echo $qstr; ?>" class="btn btn_03">수정</a>
<a href="./contact_form_update.php?w=d&amp;id=<?php echo $row['id']; ?>&amp;<?php echo $qstr; ?>" onclick="return delete_confirm(this);" class="btn btn_02">삭제</a>
</td>
</tr>
<?php
}
if ($i == 0)
echo '<tr><td colspan="8" class="empty_table">자료가 없습니다.</td></tr>';
?>
</tbody>
</table>
</div>
</form>
<?php echo get_paging(G5_IS_MOBILE ? $config['cf_mobile_pages'] : $config['cf_write_pages'], $page, $total_page, $_SERVER['SCRIPT_NAME'].'?'.$qstr.'&amp;page='); ?>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');
?>
+34
View File
@@ -0,0 +1,34 @@
<?php
include_once('./_common.php');
$contact_subject = isset($_POST['contact_subject']) ? trim($_POST['contact_subject']) : '';
$contact_name = isset($_POST['contact_name']) ? trim($_POST['contact_name']) : '';
$contact_hp = isset($_POST['contact_hp']) ? trim($_POST['contact_hp']) : '';
$contact_zip = isset($_POST['contact_zip']) ? trim($_POST['contact_zip']) : '';
$contact_addr1 = isset($_POST['contact_addr1']) ? trim($_POST['contact_addr1']) : '';
$contact_addr2 = isset($_POST['contact_addr2']) ? trim($_POST['contact_addr2']) : '';
$contact_message = isset($_POST['contact_message']) ? trim($_POST['contact_message']) : '';
if (!$contact_subject || !$contact_name || !$contact_hp || !$contact_message) {
alert('필수 입력 항목이 누락되었습니다.');
}
$sql = " insert into {$g5['contact_inquiry_table']}
set contact_subject = '{$contact_subject}',
contact_name = '{$contact_name}',
contact_hp = '{$contact_hp}',
contact_zip = '{$contact_zip}',
contact_addr1 = '{$contact_addr1}',
contact_addr2 = '{$contact_addr2}',
contact_message = '{$contact_message}',
created_at = '" . G5_TIME_YMDHIS . "',
status = 'new' ";
sql_query($sql);
$wr_id = sql_insert_id();
// 메일 발송 로직 추가 (기존 universalMailer 사용)
// ...
goto_url('./contact_list.php');
?>