first commit 2
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
// PHPMailer 라이브러리 및 필요한 Manager 클래스들을 포함합니다.
|
||||
require_once(G5_PHPMAILER_PATH . '/PHPMailerAutoload.php');
|
||||
require_once(__DIR__ . '/SmtpConfigManager.php');
|
||||
require_once(__DIR__ . '/TemplateManager.php');
|
||||
require_once(__DIR__ . '/SendLogManager.php');
|
||||
|
||||
/**
|
||||
* Class MailSender
|
||||
* SMTP 설정과 템플릿을 사용하여 메일을 발송하고 로그를 기록하는 클래스
|
||||
*/
|
||||
class MailSender {
|
||||
|
||||
/**
|
||||
* 지정된 템플릿으로 메일을 발송합니다.
|
||||
* @param string $template_code 발송할 템플릿의 고유 코드
|
||||
* @param string|array $to_email 수신자 이메일 주소 (문자열 또는 배열)
|
||||
* @param array $vars 템플릿의 변수를 치환할 값 배열
|
||||
* @param string|array $cc_email 참조 이메일 주소 (문자열 또는 배열)
|
||||
* @param string|array $bcc_email 숨은 참조 이메일 주소 (문자열 또는 배열)
|
||||
* @return bool 발송 성공 여부
|
||||
*/
|
||||
public function send($template_code, $to_email, $vars = [], $cc_email = [], $bcc_email = []) {
|
||||
$logManager = new SendLogManager();
|
||||
|
||||
// 로그 기록을 위해 배열을 문자열로 변환
|
||||
$to_email_log = is_array($to_email) ? implode(', ', $to_email) : $to_email;
|
||||
$cc_email_log = is_array($cc_email) ? implode(', ', $cc_email) : $cc_email;
|
||||
$bcc_email_log = is_array($bcc_email) ? implode(', ', $bcc_email) : $bcc_email;
|
||||
|
||||
$log_data = [
|
||||
'to_email' => $to_email_log,
|
||||
'cc_email' => $cc_email_log,
|
||||
'bcc_email_log' => $bcc_email_log,
|
||||
'subject' => '',
|
||||
'body' => '',
|
||||
'status' => 'fail', // 기본 상태를 '실패'로 설정
|
||||
'error_msg' => '',
|
||||
];
|
||||
|
||||
try {
|
||||
// 1. 사용중인 SMTP 설정 가져오기
|
||||
$smtpManager = new SmtpConfigManager();
|
||||
$smtp_config = $smtpManager->getInUse();
|
||||
if (!$smtp_config) {
|
||||
throw new Exception('사용 가능한 SMTP 설정이 없습니다.');
|
||||
}
|
||||
|
||||
// 2. 템플릿 정보 가져오기
|
||||
$templateManager = new TemplateManager();
|
||||
$template = $templateManager->getByCode($template_code);
|
||||
if (!$template) {
|
||||
throw new Exception("템플릿 코드 '{$template_code}'를 찾을 수 없습니다.");
|
||||
}
|
||||
if (!$template['is_use']) {
|
||||
throw new Exception("템플릿 '{$template['title']}'은(는) 현재 사용 중지 상태입니다.");
|
||||
}
|
||||
|
||||
// 3. 변수 치환
|
||||
$subject = $template['title'];
|
||||
$header = $template['header_html'];
|
||||
$content = $template['content'];
|
||||
$footer = $template['footer_html'];
|
||||
|
||||
// 템플릿에 저장된 기본값과 사용자 입력값을 병합 (사용자 입력값이 우선)
|
||||
$default_vars = $templateManager->getVarsByTemplateId($template['id']);
|
||||
$final_vars = array_merge($default_vars, $vars);
|
||||
|
||||
// 모든 변수를 제목, 헤더, 본문, 푸터에 적용
|
||||
foreach ($final_vars as $key => $value) {
|
||||
$search = '{' . $key . '}';
|
||||
$subject = str_replace($search, $value, $subject);
|
||||
$header = str_replace($search, $value, $header);
|
||||
$content = str_replace($search, $value, $content);
|
||||
$footer = str_replace($search, $value, $footer);
|
||||
}
|
||||
|
||||
$full_html = $header . $content . $footer;
|
||||
|
||||
$log_data['subject'] = $subject;
|
||||
$log_data['body'] = $full_html;
|
||||
|
||||
// 4. PHPMailer 설정 및 발송
|
||||
$mail = new PHPMailer;
|
||||
$mail->isSMTP();
|
||||
$mail->CharSet = 'utf-8';
|
||||
$mail->Host = $smtp_config['host'];
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = $smtp_config['username'];
|
||||
$mail->Password = $smtp_config['password'];
|
||||
$mail->SMTPSecure = $smtp_config['encryption'];
|
||||
$mail->Port = (int)$smtp_config['port'];
|
||||
|
||||
$mail->setFrom($smtp_config['from_email'], get_text(htmlspecialchars_decode(stripslashes($smtp_config['from_name']))));
|
||||
|
||||
// 수신자 추가 (배열 또는 콤마 구분 문자열 지원)
|
||||
$this->addAddresses($mail, $to_email, 'addAddress');
|
||||
|
||||
// 참조자 추가
|
||||
$this->addAddresses($mail, $cc_email, 'addCC');
|
||||
|
||||
// 숨은 참조자 추가
|
||||
$this->addAddresses($mail, $bcc_email, 'addBCC');
|
||||
|
||||
$mail->isHTML(true);
|
||||
$mail->Subject = htmlspecialchars_decode(stripslashes(get_text($subject)));
|
||||
$mail->Body = htmlspecialchars_decode(stripslashes($full_html));
|
||||
|
||||
if (!$mail->send()) {
|
||||
throw new Exception('Mailer Error: ' . $mail->ErrorInfo);
|
||||
}
|
||||
|
||||
// 성공 시 로그 데이터 업데이트
|
||||
$log_data['status'] = 'success';
|
||||
$log_data['error_msg'] = '';
|
||||
|
||||
} catch (Exception $e) {
|
||||
// 실패 시 오류 메시지 기록
|
||||
$log_data['error_msg'] = $e->getMessage();
|
||||
} finally {
|
||||
// 5. 성공/실패 여부에 관계없이 발송 로그 기록
|
||||
$logManager->addLog($log_data);
|
||||
}
|
||||
|
||||
return $log_data['status'] === 'success';
|
||||
}
|
||||
|
||||
/**
|
||||
* 템플릿을 사용하지 않고, 이미 완성된 제목과 본문으로 메일을 발송합니다. (재발송 기능용)
|
||||
* @param string|array $to_email 수신자 이메일 주소
|
||||
* @param string $subject 메일 제목
|
||||
* @param string $body 메일 본문 (HTML)
|
||||
* @param int|null $original_log_id 재발송의 대상이 되는 원본 로그 ID
|
||||
* @param string|array $cc_email 참조 이메일
|
||||
* @param string|array $bcc_email 숨은 참조 이메일
|
||||
* @return bool 발송 성공 여부
|
||||
*/
|
||||
public function sendRaw($to_email, $subject, $body, $original_log_id = null, $cc_email = [], $bcc_email = []) {
|
||||
$logManager = new SendLogManager();
|
||||
|
||||
$to_email_log = is_array($to_email) ? implode(', ', $to_email) : $to_email;
|
||||
$cc_email_log = is_array($cc_email) ? implode(', ', $cc_email) : $cc_email;
|
||||
|
||||
$log_data = [
|
||||
'to_email' => $to_email_log,
|
||||
'cc_email' => $cc_email_log,
|
||||
'subject' => $subject,
|
||||
'body' => $body,
|
||||
'status' => 'fail', // 기본 상태를 '실패'로 설정
|
||||
'error_msg' => '',
|
||||
'resend_of' => $original_log_id // 재발송 로그 ID 기록
|
||||
];
|
||||
|
||||
try {
|
||||
// 1. 사용중인 SMTP 설정 가져오기
|
||||
$smtpManager = new SmtpConfigManager();
|
||||
$smtp_config = $smtpManager->getInUse();
|
||||
if (!$smtp_config) {
|
||||
throw new Exception('사용 가능한 SMTP 설정이 없습니다.');
|
||||
}
|
||||
|
||||
// 2. 변수 치환 과정은 생략
|
||||
|
||||
// 3. PHPMailer 설정 및 발송
|
||||
$mail = new PHPMailer;
|
||||
$mail->isSMTP();
|
||||
$mail->CharSet = 'utf-8';
|
||||
$mail->Host = $smtp_config['host'];
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = $smtp_config['username'];
|
||||
$mail->Password = $smtp_config['password'];
|
||||
$mail->SMTPSecure = $smtp_config['encryption'];
|
||||
$mail->Port = (int)$smtp_config['port'];
|
||||
|
||||
// [보안/개선] 발신자 이름에 포함될 수 있는 HTML 태그를 제거합니다.
|
||||
$from_name = get_text(htmlspecialchars_decode(stripslashes($smtp_config['from_name'])));
|
||||
$mail->setFrom($smtp_config['from_email'], $from_name);
|
||||
|
||||
// 수신자, 참조, 숨은참조 추가
|
||||
$this->addAddresses($mail, $to_email, 'addAddress');
|
||||
$this->addAddresses($mail, $cc_email, 'addCC');
|
||||
$this->addAddresses($mail, $bcc_email, 'addBCC');
|
||||
|
||||
$mail->isHTML(true);
|
||||
|
||||
// [보안/개선] 로그에 저장된 제목과 본문은 이미 완성된 상태이므로 불필요한 함수 적용을 최소화합니다.
|
||||
$mail->Subject = htmlspecialchars_decode(stripslashes(get_text($subject)));
|
||||
$mail->Body = htmlspecialchars_decode(stripslashes($body));
|
||||
|
||||
if (!$mail->send()) {
|
||||
throw new Exception('Mailer Error: ' . $mail->ErrorInfo);
|
||||
}
|
||||
|
||||
// 성공 시 로그 데이터 업데이트
|
||||
$log_data['status'] = 'success';
|
||||
$log_data['error_msg'] = '';
|
||||
|
||||
} catch (Exception $e) {
|
||||
// 실패 시 오류 메시지 기록
|
||||
$log_data['error_msg'] = $e->getMessage();
|
||||
} finally {
|
||||
// 4. 성공/실패 여부에 관계없이 발송 로그 기록
|
||||
$logManager->addLog($log_data);
|
||||
}
|
||||
|
||||
return $log_data['status'] === 'success';
|
||||
}
|
||||
|
||||
/**
|
||||
* 이메일 주소 목록을 PHPMailer 객체에 추가하는 헬퍼 메소드
|
||||
* @param object $mail PHPMailer 객체
|
||||
* @param string|array $addresses 이메일 주소 (문자열 또는 배열)
|
||||
* @param string $method PHPMailer 메소드명 (addAddress, addCC, addBCC)
|
||||
*/
|
||||
private function addAddresses($mail, $addresses, $method) {
|
||||
if (empty($addresses)) return;
|
||||
|
||||
if (!is_array($addresses)) {
|
||||
// 콤마로 구분된 문자열인 경우 배열로 변환
|
||||
$addresses = explode(',', $addresses);
|
||||
}
|
||||
|
||||
foreach ($addresses as $email) {
|
||||
$email = trim($email);
|
||||
if (!empty($email)) {
|
||||
// $mail->$method($email) 형태로 호출
|
||||
$mail->$method($email);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
class SendLogManager {
|
||||
protected $table = 'g5_mail_send_log';
|
||||
|
||||
public function getTotalCount() {
|
||||
$row = sql_fetch("SELECT COUNT(*) as cnt FROM {$this->table}");
|
||||
return $row['cnt'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* [추가] 페이징된 로그 목록을 가져옵니다.
|
||||
* @param int $from_record 시작 레코드
|
||||
* @param int $page_rows 페이지당 레코드 수
|
||||
* @return array
|
||||
*/
|
||||
public function getPagedList($from_record, $page_rows) {
|
||||
$from_record = (int)$from_record;
|
||||
$page_rows = (int)$page_rows;
|
||||
|
||||
$sql = "SELECT * FROM {$this->table} ORDER BY id DESC LIMIT {$from_record}, {$page_rows}";
|
||||
$result = sql_query($sql);
|
||||
$list = [];
|
||||
while($row = sql_fetch_array($result)) {
|
||||
$list[] = $row;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function getById($id) {
|
||||
$id = (int)$id;
|
||||
return sql_fetch("SELECT * FROM {$this->table} WHERE id = '{$id}'");
|
||||
}
|
||||
|
||||
// C:/project/other/saungjin/adm/mail_manage/classes/SendLogManager.php 파일
|
||||
|
||||
public function addLog($data) {
|
||||
global $member;
|
||||
|
||||
// 넘어온 데이터를 안전하게 처리
|
||||
$to_email = sql_real_escape_string($data['to_email']);
|
||||
$cc_email = isset($data['cc_email']) ? sql_real_escape_string($data['cc_email']) : '';
|
||||
$bcc_email = isset($data['bcc_email']) ? sql_real_escape_string($data['bcc_email']) : '';
|
||||
$subject = sql_real_escape_string($data['subject']);
|
||||
$body = sql_real_escape_string($data['body']);
|
||||
$status = in_array($data['status'], ['success', 'fail']) ? $data['status'] : 'fail';
|
||||
$error_msg = isset($data['error_msg']) ? sql_real_escape_string($data['error_msg']) : '';
|
||||
$send_time = G5_TIME_YMDHIS;
|
||||
$resend_of = isset($data['resend_of']) ? (int)$data['resend_of'] : 'NULL';
|
||||
$created_by = $member['mb_id'] ?? 'guest'; // 로그인한 사용자 또는 guest
|
||||
|
||||
// [수정] install.php의 테이블 구조와 일치하도록 쿼리 수정
|
||||
$sql = "INSERT INTO {$this->table}
|
||||
(to_email, cc_email,bcc_email, subject, body, status, send_time, created_by, created_at, error_msg, resend_of)
|
||||
VALUES
|
||||
('{$to_email}', '{$cc_email}', '{$bcc_email}' ,'{$subject}', '{$body}', '{$status}', '{$send_time}', '{$created_by}', '{$send_time}', '{$error_msg}', {$resend_of})";
|
||||
|
||||
sql_query($sql);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
class SmtpConfigManager
|
||||
{
|
||||
private $table = 'g5_mail_smtp_config';
|
||||
// [추가] 로그 테이블명 변수
|
||||
private $log_table = 'g5_mail_smtp_change_log';
|
||||
|
||||
public function getAll()
|
||||
{
|
||||
$sql = "SELECT * FROM {$this->table} WHERE is_deleted = 0 ORDER BY id DESC";
|
||||
$result = sql_query($sql);
|
||||
$list = [];
|
||||
while ($row = sql_fetch_array($result)) {
|
||||
$list[] = $row;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function get($id)
|
||||
{
|
||||
$id = (int)$id;
|
||||
return sql_fetch("SELECT * FROM {$this->table} WHERE id = '{$id}' AND is_deleted = 0");
|
||||
}
|
||||
|
||||
public function getInUse()
|
||||
{
|
||||
// [추가] 사용중(is_use=1)인 첫번째 설정을 가져오는 메소드
|
||||
return sql_fetch("SELECT * FROM {$this->table} WHERE is_use = 1 AND is_deleted = 0 LIMIT 1");
|
||||
}
|
||||
|
||||
public function create($data)
|
||||
{
|
||||
global $member;
|
||||
$now = G5_TIME_YMDHIS;
|
||||
|
||||
$set_sql = [];
|
||||
$set_sql[] = " name = '" . sql_real_escape_string(trim($data['name'])) . "' ";
|
||||
$set_sql[] = " host = '" . sql_real_escape_string(trim($data['host'])) . "' ";
|
||||
$set_sql[] = " username = '" . sql_real_escape_string(trim($data['username'])) . "' ";
|
||||
$set_sql[] = " password = '" . sql_real_escape_string(trim($data['password'])) . "' ";
|
||||
$set_sql[] = " port = '" . (int)$data['port'] . "' ";
|
||||
$set_sql[] = " encryption = '" . (in_array($data['encryption'], ['none', 'ssl', 'tls']) ? $data['encryption'] : 'ssl') . "' ";
|
||||
$set_sql[] = " from_email = '" . sql_real_escape_string(trim($data['from_email'])) . "' ";
|
||||
$set_sql[] = " from_name = '" . sql_real_escape_string(trim($data['from_name'])) . "' ";
|
||||
$set_sql[] = " is_use = '" . (isset($data['is_use']) ? 1 : 0) . "' ";
|
||||
$set_sql[] = " is_deleted = '0' ";
|
||||
$set_sql[] = " created_by = '{$member['mb_id']}' ";
|
||||
$set_sql[] = " updated_by = '{$member['mb_id']}' ";
|
||||
$set_sql[] = " created_at = '{$now}' ";
|
||||
$set_sql[] = " updated_at = '{$now}' ";
|
||||
|
||||
$sql = "INSERT INTO {$this->table} SET " . implode(', ', $set_sql);
|
||||
sql_query($sql);
|
||||
|
||||
// [추가] 로그 기록
|
||||
$id = sql_insert_id();
|
||||
$details = "새로운 SMTP 설정 추가: " . sql_real_escape_string(trim($data['name']));
|
||||
$this->insertLog($id, 'insert', $member['mb_id'], $details);
|
||||
}
|
||||
|
||||
public function update($id, $data)
|
||||
{
|
||||
global $member;
|
||||
$id = (int)$id;
|
||||
$now = G5_TIME_YMDHIS;
|
||||
|
||||
$set_sql = [];
|
||||
$set_sql[] = " name = '" . sql_real_escape_string(trim($data['name'])) . "' ";
|
||||
$set_sql[] = " host = '" . sql_real_escape_string(trim($data['host'])) . "' ";
|
||||
$set_sql[] = " username = '" . sql_real_escape_string(trim($data['username'])) . "' ";
|
||||
$set_sql[] = " port = '" . (int)$data['port'] . "' ";
|
||||
$set_sql[] = " encryption = '" . (in_array($data['encryption'], ['none', 'ssl', 'tls']) ? $data['encryption'] : 'ssl') . "' ";
|
||||
$set_sql[] = " from_email = '" . sql_real_escape_string(trim($data['from_email'])) . "' ";
|
||||
$set_sql[] = " from_name = '" . sql_real_escape_string(trim($data['from_name'])) . "' ";
|
||||
$set_sql[] = " is_use = '" . (isset($data['is_use']) ? 1 : 0) . "' ";
|
||||
$set_sql[] = " updated_by = '{$member['mb_id']}' ";
|
||||
$set_sql[] = " updated_at = '{$now}' ";
|
||||
|
||||
if (!empty($data['password'])) {
|
||||
$set_sql[] = " password = '" . sql_real_escape_string(trim($data['password'])) . "' ";
|
||||
}
|
||||
|
||||
$sql = "UPDATE {$this->table} SET " . implode(', ', $set_sql) . " WHERE id = {$id}";
|
||||
sql_query($sql);
|
||||
|
||||
// [추가] 로그 기록
|
||||
$details = "SMTP 설정 수정 (ID: {$id})";
|
||||
$this->insertLog($id, 'update', $member['mb_id'], $details);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
global $member;
|
||||
$id = (int)$id;
|
||||
$now = G5_TIME_YMDHIS;
|
||||
$mb_id = sql_real_escape_string($member['mb_id']);
|
||||
|
||||
$sql = "UPDATE {$this->table} SET
|
||||
is_deleted = 1,
|
||||
updated_by = '{$mb_id}',
|
||||
updated_at = '{$now}'
|
||||
WHERE id = {$id}";
|
||||
sql_query($sql);
|
||||
|
||||
// [추가] 로그 기록
|
||||
$details = "SMTP 설정 삭제 (ID: {$id})";
|
||||
$this->insertLog($id, 'delete', $member['mb_id'], $details);
|
||||
}
|
||||
|
||||
/**
|
||||
* [추가] 변경 이력을 기록하는 private 메소드
|
||||
*/
|
||||
private function insertLog($smtp_config_id, $action, $changed_by, $details)
|
||||
{
|
||||
$smtp_config_id = (int)$smtp_config_id;
|
||||
$action = sql_real_escape_string($action);
|
||||
$changed_by = sql_real_escape_string($changed_by);
|
||||
$details = sql_real_escape_string($details);
|
||||
$change_date = G5_TIME_YMDHIS;
|
||||
|
||||
$sql = "INSERT INTO {$this->log_table}
|
||||
(smtp_config_id, `action`, changed_by, change_date, change_details)
|
||||
VALUES
|
||||
('{$smtp_config_id}', '{$action}', '{$changed_by}', '{$change_date}', '{$details}')";
|
||||
sql_query($sql);
|
||||
}
|
||||
}
|
||||
/*if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
class SmtpConfigManager
|
||||
{
|
||||
private $table = 'g5_mail_smtp_config';
|
||||
|
||||
public function getAll()
|
||||
{
|
||||
$sql = "SELECT * FROM {$this->table} WHERE is_deleted = 0 ORDER BY id DESC";
|
||||
$result = sql_query($sql);
|
||||
$list = [];
|
||||
while ($row = sql_fetch_array($result)) {
|
||||
$list[] = $row;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function get($id)
|
||||
{
|
||||
$id = (int)$id;
|
||||
return sql_fetch("SELECT * FROM {$this->table} WHERE id = '{$id}' AND is_deleted = 0");
|
||||
}
|
||||
|
||||
public function getInUse()
|
||||
{
|
||||
// [추가] 사용중(is_use=1)인 첫번째 설정을 가져오는 메소드
|
||||
return sql_fetch("SELECT * FROM {$this->table} WHERE is_use = 1 AND is_deleted = 0 LIMIT 1");
|
||||
}
|
||||
|
||||
public function create($data)
|
||||
{
|
||||
global $member;
|
||||
$now = G5_TIME_YMDHIS;
|
||||
|
||||
// [수정] sql_array_insert 함수 대신 직접 SQL 구문을 생성합니다.
|
||||
// 이 방식은 SQL 인젝션에 더 안전하고 호환성 문제가 없습니다.
|
||||
$set_sql = [];
|
||||
$set_sql[] = " name = '".sql_real_escape_string(trim($data['name']))."' ";
|
||||
$set_sql[] = " host = '".sql_real_escape_string(trim($data['host']))."' ";
|
||||
$set_sql[] = " username = '".sql_real_escape_string(trim($data['username']))."' ";
|
||||
$set_sql[] = " password = '".sql_real_escape_string(trim($data['password']))."' ";
|
||||
$set_sql[] = " port = '".(int)$data['port']."' ";
|
||||
$set_sql[] = " encryption = '".(in_array($data['encryption'], ['none','ssl','tls']) ? $data['encryption'] : 'ssl')."' ";
|
||||
$set_sql[] = " from_email = '".sql_real_escape_string(trim($data['from_email']))."' ";
|
||||
$set_sql[] = " from_name = '".sql_real_escape_string(trim($data['from_name']))."' ";
|
||||
$set_sql[] = " is_use = '".(isset($data['is_use']) ? 1 : 0)."' ";
|
||||
$set_sql[] = " is_deleted = '0' ";
|
||||
$set_sql[] = " created_by = '{$member['mb_id']}' ";
|
||||
$set_sql[] = " updated_by = '{$member['mb_id']}' ";
|
||||
$set_sql[] = " created_at = '{$now}' ";
|
||||
$set_sql[] = " updated_at = '{$now}' ";
|
||||
|
||||
$sql = "INSERT INTO {$this->table} SET " . implode(', ', $set_sql);
|
||||
sql_query($sql);
|
||||
}
|
||||
|
||||
public function update($id, $data)
|
||||
{
|
||||
global $member;
|
||||
$id = (int)$id;
|
||||
$now = G5_TIME_YMDHIS;
|
||||
|
||||
// [수정] sql_array_insert 함수 대신 직접 SQL 구문을 생성합니다.
|
||||
$set_sql = [];
|
||||
$set_sql[] = " name = '".sql_real_escape_string(trim($data['name']))."' ";
|
||||
$set_sql[] = " host = '".sql_real_escape_string(trim($data['host']))."' ";
|
||||
$set_sql[] = " username = '".sql_real_escape_string(trim($data['username']))."' ";
|
||||
$set_sql[] = " port = '".(int)$data['port']."' ";
|
||||
$set_sql[] = " encryption = '".(in_array($data['encryption'], ['none','ssl','tls']) ? $data['encryption'] : 'ssl')."' ";
|
||||
$set_sql[] = " from_email = '".sql_real_escape_string(trim($data['from_email']))."' ";
|
||||
$set_sql[] = " from_name = '".sql_real_escape_string(trim($data['from_name']))."' ";
|
||||
$set_sql[] = " is_use = '".(isset($data['is_use']) ? 1 : 0)."' ";
|
||||
$set_sql[] = " updated_by = '{$member['mb_id']}' ";
|
||||
$set_sql[] = " updated_at = '{$now}' ";
|
||||
|
||||
// 비밀번호가 입력된 경우에만 업데이트
|
||||
if (!empty($data['password'])) {
|
||||
$set_sql[] = " password = '".sql_real_escape_string(trim($data['password']))."' ";
|
||||
}
|
||||
|
||||
$sql = "UPDATE {$this->table} SET " . implode(', ', $set_sql) . " WHERE id = {$id}";
|
||||
sql_query($sql);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
global $member;
|
||||
$id = (int)$id;
|
||||
$now = G5_TIME_YMDHIS;
|
||||
|
||||
// [개선] sql_real_escape_string 을 사용하여 보안 강화
|
||||
$mb_id = sql_real_escape_string($member['mb_id']);
|
||||
|
||||
$sql = "UPDATE {$this->table} SET
|
||||
is_deleted = 1,
|
||||
updated_by = '{$mb_id}',
|
||||
updated_at = '{$now}'
|
||||
WHERE id = {$id}";
|
||||
sql_query($sql);
|
||||
}
|
||||
}*/
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
if (!defined('_GNUBOARD_')) exit;
|
||||
|
||||
class TemplateManager
|
||||
{
|
||||
protected $table = 'g5_mail_template';
|
||||
private $log_table = 'g5_mail_template_change_log';
|
||||
// [추가] 템플릿 변수 테이블명
|
||||
private $vars_table = 'g5_mail_template_vars';
|
||||
|
||||
public function getAll()
|
||||
{
|
||||
// [수정] is_use -> is_deleted 로 조건 변경
|
||||
$result = sql_query("SELECT * FROM {$this->table} WHERE is_deleted = 0 ORDER BY id DESC");
|
||||
$list = [];
|
||||
while ($row = sql_fetch_array($result)) {
|
||||
$list[] = $row;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function getById($id)
|
||||
{
|
||||
$id = (int)$id;
|
||||
return sql_fetch("SELECT * FROM {$this->table} WHERE id = '{$id}' AND is_deleted = 0 AND is_use = 1");
|
||||
}
|
||||
|
||||
public function getByCode($code)
|
||||
{
|
||||
$code = sql_real_escape_string($code);
|
||||
return sql_fetch("SELECT * FROM {$this->table} WHERE code = '{$code}' AND is_deleted = 0");
|
||||
}
|
||||
|
||||
/**
|
||||
* [추가] 특정 템플릿에 속한 모든 변수들을 가져옵니다.
|
||||
* @param int $template_id
|
||||
* @return array
|
||||
*/
|
||||
public function getVarsByTemplateId($template_id)
|
||||
{
|
||||
$template_id = (int)$template_id;
|
||||
$sql = "SELECT var_name, default_value FROM {$this->vars_table} WHERE template_id = '{$template_id}'";
|
||||
$result = sql_query($sql);
|
||||
$vars = [];
|
||||
while ($row = sql_fetch_array($result)) {
|
||||
$vars[$row['var_name']] = $row['default_value'];
|
||||
}
|
||||
return $vars;
|
||||
}
|
||||
|
||||
public function save($data)
|
||||
{
|
||||
global $member;
|
||||
|
||||
$id = isset($data['id']) ? (int)$data['id'] : 0;
|
||||
$code = sql_real_escape_string($data['code']);
|
||||
$title = sql_real_escape_string($data['title']);
|
||||
$content = $data['content']; // [주의] SQL Escape는 syncTemplateVars에서 처리
|
||||
// [추가] 헤더와 푸터 데이터를 받습니다.
|
||||
$header_html = $data['header_html'] ?? '';
|
||||
$footer_html = $data['footer_html'] ?? '';
|
||||
$is_use = isset($data['is_use']) ? 1 : 0;
|
||||
$now = G5_TIME_YMDHIS;
|
||||
$mb_id = sql_real_escape_string($member['mb_id']);
|
||||
|
||||
if ($id > 0) {
|
||||
// [수정] 업데이트 쿼리 수정
|
||||
$sql = "UPDATE {$this->table} SET
|
||||
code = '{$code}',
|
||||
title = '{$title}',
|
||||
content = '" . sql_real_escape_string($content) . "',
|
||||
header_html = '" . sql_real_escape_string($header_html) . "',
|
||||
footer_html = '" . sql_real_escape_string($footer_html) . "',
|
||||
is_use = '{$is_use}',
|
||||
updated_by = '{$mb_id}',
|
||||
updated_at = '{$now}'
|
||||
WHERE id = '{$id}'";
|
||||
sql_query($sql);
|
||||
|
||||
// [추가] 업데이트 로그 기록
|
||||
$details = "템플릿 수정 (ID: {$id}, 코드: {$code})";
|
||||
$this->insertTemplateLog($id, 'update', $mb_id, $details);
|
||||
} else {
|
||||
// [수정] 생성 쿼리 수정
|
||||
$sql = "INSERT INTO {$this->table}
|
||||
(code, title, content, header_html, footer_html, is_use, is_deleted, created_by, updated_by, created_at, updated_at)
|
||||
VALUES
|
||||
('{$code}', '{$title}', '" . sql_real_escape_string($content) . "', '" . sql_real_escape_string($header_html) . "', '" . sql_real_escape_string($footer_html) . "', '{$is_use}', 0, '{$mb_id}', '{$mb_id}', '{$now}', '{$now}')";
|
||||
sql_query($sql);
|
||||
$id = sql_insert_id(); // 새로 생성된 ID를 가져옴
|
||||
|
||||
// [추가] 생성 로그 기록
|
||||
$details = "새 템플릿 생성: " . $title;
|
||||
$this->insertTemplateLog($id, 'insert', $mb_id, $details);
|
||||
}
|
||||
|
||||
// [핵심 추가] 템플릿 변수 동기화
|
||||
$this->syncTemplateVars($id, $content, $data['variables'] ?? []);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
global $member;
|
||||
$id = (int)$id;
|
||||
$mb_id = sql_real_escape_string($member['mb_id']);
|
||||
$now = G5_TIME_YMDHIS;
|
||||
|
||||
// [참고] is_deleted 필드는 사용하지 않으므로 실제 삭제 처리합니다.
|
||||
// g5_mail_template_vars 테이블은 FOREIGN KEY (ON DELETE CASCADE) 설정으로 자동 삭제됩니다.
|
||||
sql_query("DELETE FROM {$this->table} WHERE id = '{$id}'");
|
||||
|
||||
// [수정] 삭제 로그 기록
|
||||
$details = "템플릿 삭제 (ID: {$id})";
|
||||
$this->insertTemplateLog($id, 'delete', $mb_id, $details);
|
||||
}
|
||||
|
||||
private function insertTemplateLog($template_id, $action, $changed_by, $details)
|
||||
{
|
||||
$template_id = (int)$template_id;
|
||||
$action = sql_real_escape_string($action);
|
||||
$changed_by = sql_real_escape_string($changed_by);
|
||||
$details = sql_real_escape_string($details);
|
||||
$change_date = G5_TIME_YMDHIS;
|
||||
|
||||
$sql = "INSERT INTO {$this->log_table}
|
||||
(template_id, `action`, changed_by, change_date, change_details)
|
||||
VALUES
|
||||
('{$template_id}', '{$action}', '{$changed_by}', '{$change_date}', '{$details}')";
|
||||
sql_query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* [핵심 추가] 템플릿 내용의 변수와 DB를 동기화하는 메소드
|
||||
*/
|
||||
private function syncTemplateVars($template_id, $content, $submitted_vars)
|
||||
{
|
||||
// 1. 템플릿 내용에서 현재 사용중인 모든 변수 추출 (예: {name}, {order_id})
|
||||
preg_match_all('/{(\w+)}/u', $content, $matches);
|
||||
$vars_in_content = array_unique($matches[1]);
|
||||
|
||||
// 2. 이 템플릿과 관련된 기존 변수들을 모두 삭제 (가장 간단하고 확실한 동기화 방법)
|
||||
sql_query("DELETE FROM {$this->vars_table} WHERE template_id = '{$template_id}'");
|
||||
|
||||
// 3. 내용에 존재하는 변수들만 다시 INSERT
|
||||
if (!empty($vars_in_content)) {
|
||||
$now = G5_TIME_YMDHIS;
|
||||
foreach ($vars_in_content as $var_name) {
|
||||
// 폼에서 전송된 기본값이 있으면 사용하고, 없으면 빈 문자열로 설정
|
||||
$default_value = $submitted_vars[$var_name] ?? '';
|
||||
|
||||
$sql = "INSERT INTO {$this->vars_table}
|
||||
(template_id, var_name, default_value, created_at, updated_at)
|
||||
VALUES
|
||||
('{$template_id}', '" . sql_real_escape_string($var_name) . "', '" . sql_real_escape_string($default_value) . "', '{$now}', '{$now}')";
|
||||
sql_query($sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user