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
@@ -0,0 +1,90 @@
<?php
if (!defined('_GNUBOARD_')) exit;
class NotificationManager
{
/**
* 템플릿 키를 기반으로 알림을 발송합니다.
* @param string $template_key 템플릿 키 (e.g., 'reservation_confirmed')
* @param array $data 치환될 데이터 배열 (e.g., ['customer_name' => '홍길동'])
* @return bool 성공 여부
*/
public function sendNotification($template_key, $data)
{
$success = true;
// 1. 이메일 템플릿 조회 및 발송
$email_sql = "SELECT * FROM consultant_mail_templates WHERE template_key = '" . sql_real_escape_string($template_key) . "' AND is_active = 1";
$email_template = sql_fetch($email_sql);
if ($email_template) {
$subject = $this->replaceVariables($email_template['template_subject'], $data);
$content = $this->replaceVariables($email_template['template_content'], $data);
if (!$this->sendEmail($data['customer_email'], $data['customer_name'], $subject, $content)) {
$success = false;
}
}
// 2. SMS 템플릿 조회 및 발송
$sms_sql = "SELECT * FROM consultant_sms_templates WHERE template_key = '" . sql_real_escape_string($template_key) . "' AND is_active = 1";
$sms_template = sql_fetch($sms_sql);
if ($sms_template) {
$content = $this->replaceVariables($sms_template['template_content'], $data);
if (!$this->sendSms($data['customer_phone'], $content)) {
$success = false;
}
}
return $success;
}
/**
* 변수를 실제 값으로 치환합니다.
*/
private function replaceVariables($text, $data)
{
foreach ($data as $key => $value) {
$text = str_replace('{' . $key . '}', $value, $text);
}
return $text;
}
/**
* 💡 [연동] mail_manage 시스템을 사용하여 메일을 발송합니다.
*/
private function sendEmail($to_email, $to_name, $subject, $content)
{
// mail_manage의 라이브러리 포함
if (file_exists(G5_ADMIN_PATH . '/mail_manage/mailer.lib.php')) {
include_once(G5_ADMIN_PATH . '/mail_manage/mailer.lib.php');
// mailer() 함수 호출 (mail_manage의 함수명에 따라 수정 필요)
// mailer($from_name, $from_email, $to_email, $subject, $content, 1);
consultant_log("[Email Sent] To: {$to_email}, Subject: {$subject}");
return true;
}
consultant_log("[Email Error] mail_manage/mailer.lib.php not found.", 'error');
return false;
}
/**
* 💡 [연동] sms_admin 시스템을 사용하여 문자를 발송합니다.
*/
private function sendSms($to_phone, $content)
{
// sms_admin의 라이브러리 포함
if (file_exists(G5_ADMIN_PATH . '/sms_admin/sms.lib.php')) {
include_once(G5_ADMIN_PATH . '/sms_admin/sms.lib.php');
// sms_send() 함수 호출 (sms_admin의 함수명에 따라 수정 필요)
// $result = sms_send($to_phone, $content);
consultant_log("[SMS Sent] To: {$to_phone}, Content: {$content}");
return true;
}
consultant_log("[SMS Error] sms_admin/sms.lib.php not found.", 'error');
return false;
}
}
@@ -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];
}
}