Merge branch 'master' of github.com:gnuboard/g5-update

This commit is contained in:
thisgun
2025-09-08 09:43:00 +09:00
99 changed files with 8876 additions and 260 deletions

View File

@ -1,11 +1,115 @@
function check_all(f)
{
var chk = document.getElementsByName("chk[]");
/** 공통 UI 모듈 */
window.CommonUI = {
bindTabs(tabSelector, contentSelector, options = {}) {
const tabs = document.querySelectorAll(tabSelector);
const contents = document.querySelectorAll(contentSelector);
for (i=0; i<chk.length; i++)
chk[i].checked = f.chkall.checked;
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const tabName = tab.dataset.tab;
const target = document.getElementById(`tab-${tabName}`);
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
contents.forEach(c => c.classList.add('is-hidden'));
if (target) target.classList.remove('is-hidden');
options.onChange?.(tabName, target);
});
});
}
};
function setHtml(el, markup) {
if (!el) return;
if (markup == null || markup === '') {
el.textContent = '';
return;
}
const range = document.createRange();
range.selectNodeContents(el);
el.replaceChildren(range.createContextualFragment(markup));
}
/** 팝업 관리 모듈 */
window.PopupManager = {
open(id, options = {}) {
const el = document.getElementById(id);
if (el) {
el.classList.remove('is-hidden');
this.bindOutsideClickClose(id);
if (!options.disableOutsideClose) {
this.bindOutsideClickClose(id);
} else {
this.unbindOutsideClickClose(id);
}
}
},
close(id) {
const el = document.getElementById(id);
if (el) el.classList.add('is-hidden');
},
toggle(id) {
const el = document.getElementById(id);
if (el) el.classList.toggle('is-hidden');
},
bindOutsideClickClose(id) {
const el = document.getElementById(id);
if (!el) return;
el.onclick = () => this.close(id);
},
unbindOutsideClickClose(id) {
const el = document.getElementById(id);
if (!el) return;
el.onclick = null;
},
/**
* 팝업 콘텐츠 렌더링 (타이틀, 바디, 푸터 구성)
* @param {string} title - 팝업 제목
* @param {string} body - 팝업 본문 HTML
* @param {string} [footer] - 푸터 HTML
* @param {object} [options] - 팝업 열기 옵션
*/
render(title, body, footer = '', options = {}) {
const titleEl = document.getElementById('popupTitle');
const bodyEl = document.getElementById('popupBody');
const footerEl = document.getElementById('popupFooter');
if (titleEl) titleEl.textContent = title;
if (bodyEl) setHtml(bodyEl, body);
if (footerEl) setHtml(footerEl, footer);
this.open('popupOverlay', options);
}
};
/** 형식 체크 */
function check_all(target) {
const chkboxes = document.getElementsByName("chk[]");
let chkall;
if (target && target.tagName === "FORM") {
chkall = target.querySelector('input[name="chkall"]');
} else if (target && target.type === "checkbox") {
chkall = target;
}
if (!chkall) return;
for (const checkbox of chkboxes) {
checkbox.checked = chkall.checked;
}
}
function btn_check(f, act)
{
if (act == "update") // 선택수정

View File

@ -6,11 +6,13 @@ $menu['menu100'] = array(
array('100280', '테마설정', G5_ADMIN_URL . '/theme.php', 'cf_theme', 1),
array('100290', '메뉴설정', G5_ADMIN_URL . '/menu_list.php', 'cf_menu', 1),
array('100300', '메일 테스트', G5_ADMIN_URL . '/sendmail_test.php', 'cf_mailtest'),
array('100320', '알림톡프리셋관리', G5_ADMIN_URL . '/alimtalkpreset.php', 'alimtalk_preset'),
array('100310', '팝업레이어관리', G5_ADMIN_URL . '/newwinlist.php', 'scf_poplayer'),
array('100800', '세션파일 일괄삭제', G5_ADMIN_URL . '/session_file_delete.php', 'cf_session', 1),
array('100900', '캐시파일 일괄삭제', G5_ADMIN_URL . '/cache_file_delete.php', 'cf_cache', 1),
array('100910', '캡챠파일 일괄삭제', G5_ADMIN_URL . '/captcha_file_delete.php', 'cf_captcha', 1),
array('100920', '썸네일파일 일괄삭제', G5_ADMIN_URL . '/thumbnail_file_delete.php', 'cf_thumbnail', 1),
array('100930', '회원관리파일 일괄삭제', G5_ADMIN_URL . '/member_list_file_delete.php', 'cf_memberlist', 1),
array('100500', 'phpinfo()', G5_ADMIN_URL . '/phpinfo.php', 'cf_phpinfo')
);

View File

@ -2,6 +2,7 @@
$menu['menu200'] = array(
array('200000', '회원관리', G5_ADMIN_URL . '/member_list.php', 'member'),
array('200100', '회원관리', G5_ADMIN_URL . '/member_list.php', 'mb_list'),
array('200400', '회원관리파일', G5_ADMIN_URL . '/member_list_exel.php', 'mb_list'),
array('200300', '회원메일발송', G5_ADMIN_URL . '/mail_list.php', 'mb_mail'),
array('200800', '접속자집계', G5_ADMIN_URL . '/visit_list.php', 'mb_visit', 1),
array('200810', '접속자검색', G5_ADMIN_URL . '/visit_search.php', 'mb_search', 1),

View File

@ -8,7 +8,7 @@ $menu['menu500'] = array(
array('500110', '매출현황', G5_ADMIN_URL . '/shop_admin/sale1.php', 'sst_order_stats'),
array('500100', '상품판매순위', G5_ADMIN_URL . '/shop_admin/itemsellrank.php', 'sst_rank'),
array('500120', '주문내역출력', G5_ADMIN_URL . '/shop_admin/orderprint.php', 'sst_print_order', 1),
array('500400', '재입고SMS알림', G5_ADMIN_URL . '/shop_admin/itemstocksms.php', 'sst_stock_sms', 1),
array('500400', '재입고알림', G5_ADMIN_URL . '/shop_admin/itemstocksms.php', 'sst_stock_sms', 1),
array('500300', '이벤트관리', G5_ADMIN_URL . '/shop_admin/itemevent.php', 'scf_event'),
array('500310', '이벤트일괄처리', G5_ADMIN_URL . '/shop_admin/itemeventlist.php', 'scf_event_mng'),
array('500500', '배너관리', G5_ADMIN_URL . '/shop_admin/bannerlist.php', 'scf_banner', 1),

View File

@ -14,7 +14,6 @@ $print_version = ($is_admin == 'super') ? 'Version ' . G5_GNUBOARD_VER : '';
<strong>자바스크립트를 사용하지 않음</strong>으로 설정하신 경우는 수정이나 삭제시 별도의 경고창이 나오지 않으므로 이점 주의하시기 바랍니다.
</p>
</noscript>
</div>
<footer id="ft">
<p>
@ -22,8 +21,25 @@ $print_version = ($is_admin == 'super') ? 'Version ' . G5_GNUBOARD_VER : '';
<button type="button" class="scroll_top"><span class="top_img"></span><span class="top_txt">TOP</span></button>
</p>
</footer>
</div>
<!-- 공통 레이어 팝업 컨테이너 -->
<div id="adminPopupContainer">
<div id="popupOverlay" class="popup-overlay is-hidden" onclick="PopupManager.close('popupOverlay')">
<div class="popup-content" onclick="event.stopPropagation()">
<div class="popup-header">
<strong id="popupTitle" class="popup-title"></strong>
<button type="button" class="popup-close-btn" onclick="PopupManager.close('popupOverlay')">
<i class="fa fa-close"></i><span class="sound_only">팝업 닫기</span>
</button>
</div>
<div class="popup-body" id="popupBody">
<!-- 동적으로 내용 주입 -->
</div>
<div class="popup-footer" id="popupFooter">
<!-- 버튼 등 동적으로 -->
</div>
</div>
</div>
</div>
<script>

57
adm/alimtalkpreset.php Normal file
View File

@ -0,0 +1,57 @@
<?php
$sub_menu = '100320';
include_once('./_common.php');
include_once(G5_KAKAO5_PATH.'/kakao5.lib.php');
auth_check_menu($auth, $sub_menu, "r");
$g5['title'] = '알림톡 프리셋 관리';
include_once(G5_ADMIN_PATH.'/admin.head.php');
// 영카트(쇼핑몰) 사용 여부 확인
$has_shop = defined('G5_USE_SHOP') && G5_USE_SHOP;
// SQL 조건
$sql_search = $has_shop ? 'where (1)' : "WHERE kp_category <> '쇼핑몰'";
if ($stx) {
$sql_search .= " and ( ";
switch ($sfl) {
default:
$sql_search .= " ({$sfl} like '%{$stx}%') ";
break;
}
$sql_search .= " ) ";
}
if ($sst) {
$sql_order = " order by {$sst} {$sod} ";
} else {
$sql_order = " order by kp_id asc ";
}
// 프리셋 테이블 조회
$result = sql_query("SELECT * FROM {$g5['kakao5_preset_table']} {$sql_search} {$sql_order}");
?>
<?php if (!sql_query("DESC {$g5['kakao5_preset_table']}", false)) { ?>
<h2 class="h2_frm">카카오톡 프리셋 DB가 설치되지 않았습니다.</h2>
<div class="local_desc01 local_desc">
<p>카카오톡 프리셋 DB가 설치되지 않아 프리셋을 사용할 수 없습니다.
<br><a href="<?php echo G5_ADMIN_URL;?>/dbupgrade.php" class="btn_frmline">DB 업그레이드</a>를 진행해주세요.</p>
</div>
<?php include_once(G5_ADMIN_PATH.'/admin.tail.php'); exit; ?>
<?php } ?>
<?php if ($config['cf_kakaotalk_use'] == 'popbill') { // 팝빌 사용
include_once(G5_ADMIN_PATH.'/alimtalkpreset_popbill.php');
} else { ?>
<h2 class="h2_frm">카카오톡 발송 서비스를 사용할 수 없습니다.</h2>
<div class="local_desc01 local_desc">
<p>카카오톡 을 사용하지 않고 있기 때문에, 카카오톡 전송을 할 수 없습니다.
<br>카카오톡 사용 설정은 <a href="<?php echo G5_ADMIN_URL;?>/config_form.php#anc_cf_mail" class="btn_frmline">환경설정 &gt; 기본환경설정 &gt; 기본알림환경</a> 에서 카카오톡 사용을 변경해 주셔야 사용하실수 있습니다.</p>
</div>
<?php } ?>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');

View File

@ -0,0 +1,300 @@
<?php
/*
* 팝빌 - 알림톡 프리셋 설정
*/
// 템플릿 목록 조회
$templates = get_popbill_template_list();
add_javascript('<script src="'.G5_JS_URL.'/kakao5.js"></script>', 1); // 카카오톡5 솔루션 js 추가
?>
<?php
// 팝빌 연결이 제대로 안되었을 경우 아래와 같이 표시
$check_popbill = get_popbill_service_info();
if(isset($check_popbill['error'])) { ?>
<h2 class="h2_frm">팝빌 카카오톡 발송 서비스를 사용할 수 없습니다.</h2>
<div class="local_desc01 local_desc">
<p>팝빌 서비스 설정이 되어 있지 않아, 프리셋 서비스를 사용할 수 없습니다.
<br>팝빌 설정은 <a href="<?php echo G5_ADMIN_URL;?>/config_form.php#anc_cf_mail" class="btn_frmline">환경설정 &gt; 기본환경설정 &gt; 기본알림환경</a> 에서 확인 및 설정해 주셔야 사용하실 수 있습니다.</p><br>
<p>* 설정 오류 내용 : <span style="color:red"><?php echo $check_popbill["error"];?></span></p>
</div>
<?php } else { ?>
<div class="local_desc01 local_desc">
<p><a href="#" class="btn_template_manage" id="btnTemplateManageInfo">템플릿관리</a>를 통해 신청 후 승인된 템플릿만 사용가능합니다.<br>템플릿 내용 작성 시, 동일한 <b>[구분]</b>에 속한 변수만 사용 가능하며, 아래에 제공된 변수 외의 항목을 입력할 경우 적용되지 않습니다.</p><br>
<p>아래 표의 <b>#{변수명}</b>만 템플릿 내용에 사용할 수 있으며, 실제 발송 시 값으로 자동 치환됩니다.<br><span style="color:#888;">※ 표에 없는 변수는 치환되지 않습니다.</span></p>
<p id="variable_toggle" class="variable_toggle" style="cursor:pointer; font-weight:bold;">[사용 가능한 변수 리스트<span class="btn_toggle_text" style="font-weight:normal;">▼</span>]</p>
<div id="variable_table" class="variable_table">
<table class="tbl_head01 tbl_wrap">
<caption>제공 변수 목록</caption>
<thead>
<tr>
<th scope="col">구분</th>
<th scope="col">변수명</th>
<th scope="col">설명</th>
</tr>
</thead>
<tbody>
<?php
// [정의] $kakao5_preset_variable_list - extend/kakao5.extend.php
if (!empty($kakao5_preset_variable_list) && is_array($kakao5_preset_variable_list)) {
foreach ($kakao5_preset_variable_list as $category) {
$cat_name = isset($category['category']) ? $category['category'] : '';
$vars = isset($category['variables']) ? $category['variables'] : [];
$rowspan = count($vars);
foreach ($vars as $idx => $var) {
?>
<tr>
<?php if ($idx === 0) { ?>
<td rowspan="<?php echo $rowspan; ?>"><?php echo htmlspecialchars($cat_name); ?></td>
<?php } ?>
<td><?php echo htmlspecialchars($var['name'] ?? ''); ?></td>
<td style="text-align:left;"><?php echo $var['description'] ?? ''; ?></td>
</tr>
<?php
}
}
}
?>
</tbody>
</table>
</div>
<br>
<p>아래 표의 <b>#{버튼링크명}</b>은 버튼에 사용할 수 있으며, 실제 발송 시 지정된 URL로 자동 치환됩니다.<br><span style="color:#888;">※ 표에 없는 버튼 링크 변수는 치환되지 않습니다. 등록 시 [<b>https://#{버튼링크명}</b>]으로 작성하시면 됩니다.</span></p>
<p id="button_link_toggle" class="button_link_toggle" style="cursor:pointer; font-weight:bold;">[버튼 링크 치환 리스트<span class="button_link_toggle_text" style="font-weight:normal;">▼</span>]</p>
<div id="button_link_table" class="variable_table">
<table class="tbl_head01 tbl_wrap">
<caption>제공 변수 목록</caption>
<thead>
<tr>
<th scope="col">버튼링크명</th>
<th scope="col">설명</th>
</tr>
</thead>
<tbody>
<?php
// [정의] $kakao5_preset_button_links - extend/kakao5.extend.php
if (!empty($kakao5_preset_button_links) && is_array($kakao5_preset_button_links)) {
foreach ($kakao5_preset_button_links as $key => $val) {
?>
<tr>
<td><?php echo htmlspecialchars($key); ?></td>
<td style="text-align:left;"><?php echo isset($val['description']) ? $val['description'] : ''; ?><br>
<?php if (isset($val['url'])) { ?>
<span style="color:#888;">* URL: <?php echo htmlspecialchars($val['url']); ?></span>
<?php } ?>
</td>
</tr>
<?php
}
}
?>
</tbody>
</table>
</div>
</div>
<div class="local_desc01 local_desc">
<p><b>* 관리자 휴대폰번호</b> : 관리자로 설정된 <b>[<?php echo $config['cf_admin'];?>]</b>의 <b>휴대폰 번호</b>를 사용합니다.</p>
<p><b>* 그룹 관리자 휴대폰번호</b> : 그룹 관리자로 지정된 아이디의 <b>휴대폰 번호</b>를 사용합니다.</p>
<p><b>* 게시판 관리자 휴대폰번호</b> : 게시판 관리자로 지정된 아이디의 <b>휴대폰 번호</b>를 사용합니다.</p>
</div>
<?php if (empty($config['cf_req_hp'])) { ?>
<div class="admin_pg_notice od_test_caution">
<p>
<?php
$link = '<br><a href="'.G5_ADMIN_URL.'/config_form.php#anc_cf_join">환경설정 &gt; 기본환경설정 &gt; 회원가입</a>';
if (!empty($config['cf_use_hp'])) {
// 보이기만 설정된 경우
echo '<b>[휴대폰번호 입력]</b>이 <b>[보이기]</b>로 설정되어 있습니다. 일부 회원은 휴대폰 번호를 입력하지 않아 발송이 제한될 수 있습니다.'
. $link . '에서 <b>[필수입력]</b>으로 설정하는 것을 권장합니다.';
} else {
// 둘 다 설정 안 된 경우
echo '<b>[휴대폰번호 입력]</b>이 <b>[보이기]</b> 또는 <b>[필수입력]</b>으로 설정되어 있지 않습니다. 현재 상태에서는 알림톡 발송이 불가능합니다.'
. $link . '에서 반드시 <b>[보이기]</b>나 <b>[필수입력]</b> 중 하나 이상으로 설정해야 합니다.';
}
?>
</p>
</div>
<?php } ?>
<form name="falimtalkpreset" action="./alimtalkpresetupdate.php" method="post" enctype="MULTIPART/FORM-DATA">
<input type="hidden" name="token" value="">
<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 ?>">
<section id="anc_scf_customer">
<div class="tbl_head01 tbl_wrap">
<table>
<caption>알림톡 프리셋 목록</caption>
<thead>
<tr>
<th scope="col"><?php echo subject_sort_link('kp_active') ?>사용여부</a></th>
<th scope="col"><?php echo subject_sort_link('kp_category') ?>구분</a></th>
<th scope="col">발송시점</th>
<th scope="col"><?php echo subject_sort_link('kp_type') ?>대상</a></th>
<th scope="col">템플릿 명</th>
<th scope="col">미리보기</th>
<th scope="col">버튼정보</th>
<th scope="col">문자대체발송</th>
</tr>
</thead>
<tbody>
<?php
for ($ci=0; $row=sql_fetch_array($result); $ci++) {
$bg = 'bg'.($ci%2);
?>
<tr class="<?php echo $bg; ?>">
<td class="td_chk2">
<label class="preset-toggle">
<input type="checkbox" name="kp_active[<?php echo $row['kp_id']; ?>]" value="1" <?php echo $row['kp_active'] == '1' ? 'checked' : ''; ?> onchange="toggleTemplateFields(<?php echo $row['kp_id']; ?>)">
<span class="preset-slider"></span>
</label>
</td>
<td class="td_chk2"><?php echo get_sanitize_input($row['kp_category']); ?></td>
<td class="td_cnt"><?php echo get_sanitize_input($row['kp_preset_name']); ?></td>
<td class="td_chk2"><?php echo $row['kp_type']; ?></td>
<td class="td_category1">
<select name="kp_template_name[<?php echo $row['kp_id']; ?>]" id="template_<?php echo $row['kp_id']; ?>" style="min-width: 350px;">
<option value="">템플릿 선택</option>
<?php
$template_content = '';
$buttons = '';
if (!empty($templates) && is_array($templates)) {
foreach ($templates as $tpl) {
$tplName = $tpl->templateName ?? '';
$tplCode = $tpl->templateCode ?? '';
if (empty($tplCode)) continue;
$isSelected = ($row['kp_template_name'] == $tplCode);
if ($isSelected) {
$template_content = $tpl->template;
$buttons = $tpl->btns;
}
echo '<option value="' . $tplCode . '" ' . ($isSelected ? 'selected' : '') . '>[' . ($tpl->plusFriendID ?? '') . "] ". $tplName . ' (' . $tplCode . ')' . '</option>';
}
}
?>
</select>
</td>
<!-- 템플릿 보기 버튼 추가 -->
<td class="td_cnt">
<?php if (!empty($row['kp_template_name'])) { ?>
<button type="button" class="btn_template_preview_open">템플릿보기</button>
<div class="template_preview">
<div class="template_preview_txt"><?php echo nl2br($template_content); ?></div>
<button type="button" class="btn_template_preview_close">X 닫기</button>
</div>
<?php } ?>
</td>
<!-- 버튼 정보 -->
<td class="td_addr td_odrnum">
<?php if (!empty($buttons)) { ?>
<?php foreach ($buttons as $index => $button) {
echo '<strong>[' . $button->n . ']</strong><br>';
if ($button->t == 'DS') { // 배송조회 버튼
echo '<span style="color:#888;">· 카카오톡검색 링크 버튼 자동생성</span><br>';
}else{
echo ($button->t == 'AL' ? '· iOS링크: ' : ($button->t == 'WL' ? '· Mobile링크: ' : '· 링크: ')) . $button->u1 .
($button->u2 ? '<br>' . ($button->t == 'AL' ? '· Android링크: ' : ($button->t == 'WL' ? '· PC링크: ' : '· 링크2: ')) . $button->u2 : '') .
($button->tg ? '<br>· 아웃링크: ' . $button->tg : '') . '<br>';
}
} ?>
<?php } ?>
</td>
<td class="td_category1">
<select name="kp_alt_send[<?php echo $row['kp_id']; ?>]" id="alt_send_<?php echo $row['kp_id']; ?>" style="min-width: 150px;">
<option value="1" <?php echo $row['kp_alt_send'] == '1' ? 'selected' : ''; ?>>대체문자발송</option>
<option value="0" <?php echo $row['kp_alt_send'] == '0' ? 'selected' : ''; ?>>사용안함</option>
</select>
</td>
</tr>
<?php }
if ($ci == 0) echo '<tr><td colspan="7" class="empty_table">등록된 프리셋이 없습니다.</td></tr>';
?>
</tbody>
</table>
</div>
</section>
<!-- 상단 버튼 [템플릿관리, 전송내역, 일괄수정] -->
<div class="btn_fixed_top">
<a href="#" class="btn btn_02 btn_template_manage" id="btnTemplateManage">템플릿관리</a>
<a href="#" class="btn btn_02 btn_send_manage" id="btnSendManage">전송내역</a>
<input type="submit" value="일괄수정" class="btn_submit btn" accesskey="s">
</div>
</form>
<script>
document.addEventListener('DOMContentLoaded', () => {
// 템플릿 미리보기 열기
document.querySelectorAll('.btn_template_preview_open').forEach(button => {
button.addEventListener('click', () => {
// 모든 preview 닫기
document.querySelectorAll('.template_preview').forEach(preview => {
preview.classList.remove('is-visible');
});
const previewBox = button.nextElementSibling;
if (previewBox?.classList.contains('template_preview')) previewBox.classList.add('is-visible');
});
});
// 템플릿 미리보기 닫기
document.querySelectorAll('.btn_template_preview_close').forEach(closeBtn => {
closeBtn.addEventListener('click', () => {
const previewBox = closeBtn.closest('.template_preview');
if (previewBox) previewBox.classList.remove('is-visible')
});
});
// 변수 리스트 및 버튼 링크 리스트 토글 함수 리팩토링
function setupToggleSection(toggleId, tableId, toggleTextClass = '.btn_toggle_text') {
const toggleBtn = document.getElementById(toggleId);
const table = document.getElementById(tableId);
if (toggleBtn && table) {
toggleBtn.addEventListener('click', () => {
const toggleText = toggleBtn.querySelector(toggleTextClass);
table.classList.toggle('is-visible');
const isVisible = table.classList.contains('is-visible');
if (toggleText) toggleText.textContent = isVisible ? '▲' : '▼';
});
}
}
setupToggleSection('variable_toggle', 'variable_table');
setupToggleSection('button_link_toggle', 'button_link_table');
// 템플릿 관리 팝업: [정의] openKakao5PopupFromAjax() - js/kakao5.js
document.querySelectorAll('#btnTemplateManageInfo, #btnTemplateManage').forEach(btn => {
btn.addEventListener('click', async(e) => {
e.preventDefault();
await openKakao5PopupFromAjax('<?php echo G5_KAKAO5_URL; ?>', 1);
});
});
// 전송내역 팝업: [정의] openKakao5PopupFromAjax() - js/kakao5.js
document.querySelectorAll('#btnSendManage').forEach(btn => {
btn.addEventListener('click', async(e) => {
e.preventDefault();
await openKakao5PopupFromAjax('<?php echo G5_KAKAO5_URL; ?>', 2);
});
});
});
</script>
<?php } ?>

View File

@ -0,0 +1,37 @@
<?php
$sub_menu = "100320";
include_once('./_common.php');
auth_check_menu($auth, $sub_menu, "w");
check_demo();
check_admin_token();
$g5['title'] = "알림톡 프리셋 관리";
// 알림톡 프리셋 일괄 업데이트
$kp_active = isset($_REQUEST['kp_active']) ? $_REQUEST['kp_active'] : array();
$kp_template_name = isset($_REQUEST['kp_template_name']) ? $_REQUEST['kp_template_name'] : array();
$kp_alt_send = isset($_REQUEST['kp_alt_send']) ? $_REQUEST['kp_alt_send'] : array();
// DB에서 전체 프리셋 목록 조회
$presets = array();
$sql = "SELECT kp_id, kp_active, kp_template_name, kp_alt_send FROM {$g5['kakao5_preset_table']}";
$result = sql_query($sql);
for($i=0; $row=sql_fetch_array($result); $i++) {
$kp_id = $row['kp_id'];
$active = isset($kp_active[$kp_id]) ? (int)$kp_active[$kp_id] : 0;
$template_name = isset($kp_template_name[$kp_id]) ? sql_escape_string($kp_template_name[$kp_id]) : '';
$alt_send = isset($kp_alt_send[$kp_id]) ? (int)$kp_alt_send[$kp_id] : 0;
// 값이 하나라도 다르면 UPDATE
if ($row['kp_active'] != $active || $row['kp_template_name'] != $template_name || $row['kp_alt_send'] != $alt_send) {
$sql = "UPDATE {$g5['kakao5_preset_table']} SET kp_active = '{$active}', kp_template_name = '{$template_name}', kp_alt_send = '{$alt_send}' WHERE kp_id = '{$kp_id}'";
sql_query($sql);
}
}
goto_url(G5_ADMIN_URL.'/alimtalkpreset.php?' . $qstr);

View File

@ -112,6 +112,7 @@ $sql = " insert into {$g5['board_table']}
bo_notice = '{$board['bo_notice']}',
bo_upload_count = '{$board['bo_upload_count']}',
bo_use_email = '{$board['bo_use_email']}',
bo_use_kakaotalk = '{$board['bo_use_kakaotalk']}',
bo_use_cert = '{$board['bo_use_cert']}',
bo_use_sns = '{$board['bo_use_sns']}',
bo_use_captcha = '{$board['bo_use_captcha']}',

View File

@ -89,6 +89,11 @@ if (!isset($board['bo_select_editor'])) {
sql_query(" ALTER TABLE `{$g5['board_table']}` ADD `bo_select_editor` VARCHAR(50) NOT NULL DEFAULT '' AFTER `bo_use_dhtml_editor` ", false);
}
// SMS/알림톡 사용 여부 추가
if (!isset($board['bo_use_kakaotalk'])) {
sql_query(" ALTER TABLE `{$g5['board_table']}` ADD `bo_use_kakaotalk` VARCHAR(50) NOT NULL DEFAULT '' AFTER `bo_use_email` ", false);
}
$board_default = array(
'bo_mobile_subject'=>'',
'bo_device'=>'',
@ -702,6 +707,19 @@ $pg_anchor = '<ul class="anchor">
<label for="chk_all_use_email">전체적용</label>
</td>
</tr>
<tr>
<th scope="row"><label for="bo_use_kakaotalk">SMS/알림톡 사용</label></th>
<td>
<input type="checkbox" name="bo_use_kakaotalk" value="1" id="bo_use_kakaotalk" <?php echo $board['bo_use_kakaotalk']?'checked':''; ?>>
사용
</td>
<td class="td_grpset">
<input type="checkbox" name="chk_grp_use_kakaotalk" value="1" id="chk_grp_use_kakaotalk">
<label for="chk_grp_use_kakaotalk">그룹적용</label>
<input type="checkbox" name="chk_all_use_kakaotalk" value="1" id="chk_all_use_kakaotalk">
<label for="chk_all_use_kakaotalk">전체적용</label>
</td>
</tr>
<tr>
<th scope="row"><label for="bo_use_cert">본인확인 사용</label></th>
<td>

View File

@ -121,6 +121,7 @@ $bo_use_list_view = isset($_POST['bo_use_list_view']) ? (int) $_POST['bo_use_lis
$bo_use_list_file = isset($_POST['bo_use_list_file']) ? (int) $_POST['bo_use_list_file'] : 0;
$bo_use_list_content = isset($_POST['bo_use_list_content']) ? (int) $_POST['bo_use_list_content'] : 0;
$bo_use_email = isset($_POST['bo_use_email']) ? (int) $_POST['bo_use_email'] : 0;
$bo_use_kakaotalk = isset($_POST['bo_use_kakaotalk']) ? (int) $_POST['bo_use_kakaotalk'] : 0;
$bo_use_sns = isset($_POST['bo_use_sns']) ? (int) $_POST['bo_use_sns'] : 0;
$bo_use_captcha = isset($_POST['bo_use_captcha']) ? (int) $_POST['bo_use_captcha'] : 0;
$bo_table_width = isset($_POST['bo_table_width']) ? (int) $_POST['bo_table_width'] : 0;
@ -223,6 +224,7 @@ $sql_common = " gr_id = '{$gr_id}',
bo_use_list_file = '{$bo_use_list_file}',
bo_use_list_content = '{$bo_use_list_content}',
bo_use_email = '{$bo_use_email}',
bo_use_kakaotalk = '{$bo_use_kakaotalk}',
bo_use_cert = '{$bo_use_cert}',
bo_use_sns = '{$bo_use_sns}',
bo_use_captcha = '{$bo_use_captcha}',
@ -407,6 +409,7 @@ if (is_checked('chk_grp_use_list_view')) $grp_fields .= " , bo_use_list_v
if (is_checked('chk_grp_use_list_file')) $grp_fields .= " , bo_use_list_file = '{$bo_use_list_file}' ";
if (is_checked('chk_grp_use_list_content')) $grp_fields .= " , bo_use_list_content = '{$bo_use_list_content}' ";
if (is_checked('chk_grp_use_email')) $grp_fields .= " , bo_use_email = '{$bo_use_email}' ";
if (is_checked('chk_grp_use_kakaotalk')) $grp_fields .= " , bo_use_kakaotalk = '{$bo_use_kakaotalk}' ";
if (is_checked('chk_grp_use_cert')) $grp_fields .= " , bo_use_cert = '{$bo_use_cert}' ";
if (is_checked('chk_grp_use_sns')) $grp_fields .= " , bo_use_sns = '{$bo_use_sns}' ";
if (is_checked('chk_grp_use_captcha')) $grp_fields .= " , bo_use_captcha = '{$bo_use_captcha}' ";
@ -497,6 +500,7 @@ if (is_checked('chk_all_use_list_view')) $all_fields .= " , bo_use_list_v
if (is_checked('chk_all_use_list_file')) $all_fields .= " , bo_use_list_file = '{$bo_use_list_file}' ";
if (is_checked('chk_all_use_list_content')) $all_fields .= " , bo_use_list_content = '{$bo_use_list_content}' ";
if (is_checked('chk_all_use_email')) $all_fields .= " , bo_use_email = '{$bo_use_email}' ";
if (is_checked('chk_all_use_kakaotalk')) $all_fields .= " , bo_use_kakaotalk = '{$bo_use_kakaotalk}' ";
if (is_checked('chk_all_use_cert')) $all_fields .= " , bo_use_cert = '{$bo_use_cert}' ";
if (is_checked('chk_all_use_sns')) $all_fields .= " , bo_use_sns = '{$bo_use_sns}' ";
if (is_checked('chk_all_use_captcha')) $all_fields .= " , bo_use_captcha = '{$bo_use_captcha}' ";

View File

@ -8,6 +8,8 @@ if ($is_admin != 'super') {
alert('최고관리자만 접근 가능합니다.');
}
include_once(G5_KAKAO5_PATH.'/kakao5.lib.php'); // 카카오톡 설정 확인
// https://github.com/gnuboard/gnuboard5/issues/296 이슈처리
$sql = " select * from {$g5['config_table']} limit 1";
$config = sql_fetch($sql);
@ -422,6 +424,44 @@ if (!isset($config['cf_cert_kcp_enckey'])) {
$config['cf_cert_kcp_enckey'] = '';
}
// 카카오톡 설정 필드 추가
if (!isset($config['cf_kakaotalk_use'])) {
sql_query(
" ALTER TABLE `{$g5['config_table']}`
ADD `cf_kakaotalk_use` varchar(50) NOT NULL DEFAULT '' AFTER `cf_recaptcha_secret_key`,
ADD `cf_kakaotalk_corpnum` varchar(50) NOT NULL DEFAULT '' AFTER `cf_kakaotalk_use`,
ADD `cf_kakaotalk_sender_hp` varchar(50) NOT NULL DEFAULT '' AFTER `cf_kakaotalk_corpnum`,
ADD `cf_popbill_userid` varchar(100) NOT NULL DEFAULT '' AFTER `cf_kakaotalk_sender_hp`,
ADD `cf_popbill_link_id` varchar(100) NOT NULL DEFAULT '' AFTER `cf_popbill_userid`,
ADD `cf_popbill_secretkey` varchar(255) NOT NULL DEFAULT '' AFTER `cf_popbill_link_id` ",
true
);
}
// 광고성 정보 수신 동의 사용 필드 추가
if (!isset($config['cf_use_promotion'])) {
sql_query(
" ALTER TABLE `{$g5['config_table']}`
ADD `cf_use_promotion` tinyint(1) NOT NULL DEFAULT '0' AFTER `cf_privacy` ",
true
);
}
// 광고성 정보 수신 동의 여부 필드 추가 + 메일 / SMS 수신 일자 추가
if (!isset($member['mb_marketing_agree'])) {
sql_query(
" ALTER TABLE `{$g5['member_table']}`
ADD `mb_marketing_agree` tinyint(1) NOT NULL DEFAULT '0' AFTER `mb_scrap_cnt`,
ADD `mb_marketing_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER `mb_marketing_agree`,
ADD `mb_thirdparty_agree` tinyint(1) NOT NULL DEFAULT '0' AFTER `mb_marketing_date`,
ADD `mb_thirdparty_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER `mb_thirdparty_agree`,
ADD `mb_agree_log` TEXT NOT NULL AFTER `mb_thirdparty_date`,
ADD `mb_mailling_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER `mb_mailling`,
ADD `mb_sms_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER `mb_sms` ",
true
);
}
if (!$config['cf_faq_skin']) {
$config['cf_faq_skin'] = "basic";
}
@ -438,10 +478,10 @@ $pg_anchor = '<ul class="anchor">
<li><a href="#anc_cf_join">회원가입</a></li>
<li><a href="#anc_cf_cert">본인확인</a></li>
<li><a href="#anc_cf_url">짧은주소</a></li>
<li><a href="#anc_cf_mail">기본메일환경</a></li>
<li><a href="#anc_cf_article_mail">글작성메일</a></li>
<li><a href="#anc_cf_join_mail">가입메일</a></li>
<li><a href="#anc_cf_vote_mail">투표메일</a></li>
<li><a href="#anc_cf_mail">기본알림환경</a></li>
<li><a href="#anc_cf_article_mail">글작성알림</a></li>
<li><a href="#anc_cf_join_mail">가입알림</a></li>
<li><a href="#anc_cf_vote_mail">투표알림</a></li>
<li><a href="#anc_cf_sns">SNS</a></li>
<li><a href="#anc_cf_lay">레이아웃 추가설정</a></li>
<li><a href="#anc_cf_sms">SMS</a></li>
@ -963,6 +1003,17 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
<th scope="row"><label for="cf_privacy">개인정보처리방침</label></th>
<td colspan="3"><textarea id="cf_privacy" name="cf_privacy" rows="10"><?php echo html_purifier($config['cf_privacy']); ?></textarea></td>
</tr>
<tr>
<th scope="row"><label for="cf_use_promotion">회원가입 약관 동의에<br>광고성 정보 수신 동의 표시 여부</label></th>
<td colspan="3">
<?php echo help('<b>광고성 정보 수신 · 마케팅 목적의 개인정보 수집 및 이용 · 개인정보 제 3자 제공</b> 여부를 설정합니다. <b>SMS 또는 카카오톡</b> 사용 시 <b>개인정보 제3자 제공</b>이 활성화됩니다.'); ?>
<?php echo help('동의한 회원에게 <b>카카오톡(친구톡)·문자</b>로 광고성 메시지를 발송할 수 있습니다.'); ?>
<?php echo help('<b>휴대전화번호</b> 사용을 위해서는 <b>기본환경설정 > 회원가입 > 휴대전화번호 입력</b>을 <b>[보이기]</b> 또는 <b>[필수입력]</b>으로 설정해야 하며, 미설정 시 수집이 불가합니다.'); ?>
<?php echo help('* 「정보통신망이용촉진및정보보호등에관한법률」에 따라 <b>광고성 정보 수신 동의</b>를 매 2년마다 반드시 확인해야 합니다.'); ?>
<input type="checkbox" name="cf_use_promotion" value="1" id="cf_use_promotion" <?php echo $config['cf_use_promotion'] ? 'checked' : ''; ?>>
<label for="cf_use_promotion">사용</label>
</td>
</tr>
</tbody>
</table>
</div>
@ -1105,12 +1156,12 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
?>
<section id="anc_cf_mail">
<h2 class="h2_frm">기본 메일 환경 설정</h2>
<h2 class="h2_frm">기본 알림 환경 설정</h2>
<?php echo $pg_anchor ?>
<div class="tbl_frm01 tbl_wrap">
<table>
<caption>기본 메일 환경 설정</caption>
<caption>기본 알림 환경 설정</caption>
<colgroup>
<col class="grid_4">
<col>
@ -1138,18 +1189,85 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
<input type="checkbox" name="cf_formmail_is_member" value="1" id="cf_formmail_is_member" <?php echo $config['cf_formmail_is_member'] ? 'checked' : ''; ?>> 회원만 사용
</td>
</tr>
<tr>
<th scope="row"><label for="cf_kakaotalk_use">카카오톡 사용</label></th>
<td>
<?php echo help("카카오톡 발송 서비스 회사를 선택하십시오. 서비스 회사를 선택하지 않으면, 카카오톡 발송 기능이 동작하지 않습니다."); ?>
<select name="cf_kakaotalk_use" id="cf_kakaotalk_use">
<option value="" <?php echo get_selected($config['cf_kakaotalk_use'], ''); ?>>사용안함</option>
<option value="popbill" <?php echo get_selected($config['cf_kakaotalk_use'], 'popbill'); ?>>팝빌</option>
</select>
</td>
</tr>
<tr>
<th scope="row">사업자등록번호</th>
<td>
<?php echo help('서비스 등록 시 사용했던 사업자등록번호를 입력하세요.'); ?>
<input type="text" name="cf_kakaotalk_corpnum" id="cf_kakaotalk_corpnum" value="<?php echo get_sanitize_input($config['cf_kakaotalk_corpnum']); ?>" class="frm_input" size="30">
</td>
</tr>
<tr>
<th scope="row">회신번호</th>
<td>
<?php echo help('대체문자 발송 시 사용할 회신번호를 입력하세요.'); ?>
<input type="text" name="cf_kakaotalk_sender_hp" id="cf_kakaotalk_sender_hp" value="<?php echo get_sanitize_input($config['cf_kakaotalk_sender_hp']); ?>" class="frm_input" size="30">
</td>
</tr>
<tr>
<th scope="row"><label for="cf_popbill_userid">팝빌 회원아이디</label></th>
<td>
<?php echo help('팝빌에 가입한 회원 아이디를 입력하세요.'); ?>
<input type="text" name="cf_popbill_userid" id="cf_popbill_userid" value="<?php echo get_sanitize_input($config['cf_popbill_userid']); ?>" class="frm_input" size="30">
</td>
</tr>
<tr>
<th scope="row"><label for="cf_popbill_link_id">팝빌 링크아이디(LinkID)</label></th>
<td>
<?php echo help('팝빌에서 발급한 API KEY - 링크아이디(LinkID)를 입력하세요.'); ?>
<input type="text" name="cf_popbill_link_id" id="cf_popbill_link_id" value="<?php echo get_sanitize_input($config['cf_popbill_link_id']); ?>" class="frm_input" size="30">
</td>
</tr>
<tr>
<th scope="row"><label for="cf_popbill_secretkey">팝빌 비밀키(SecretKey)</label></th>
<td>
<?php echo help('팝빌에서 발급한 API KEY - 비밀키(SecretKey)를 입력하세요.'); ?>
<input type="text" name="cf_popbill_secretkey" id="cf_popbill_secretkey" value="<?php echo get_sanitize_input($config['cf_popbill_secretkey']); ?>" class="frm_input" size="60">
</td>
</tr>
<tr>
<th scope="row"><label for="cf_phone">팝빌 설정 확인 및 포인트 조회</label></th>
<td>
<!-- 팝빌 설정 확인 및 잔여포인트 조회 -->
<?php echo help("팝빌 설정 정보를 확인하고, 잔여 포인트를 조회할 수 있습니다.<br>설정 확인 버튼을 클릭하면 팝빌 API와의 연결 상태 및 포인트 정보를 확인할 수 있습니다."); ?>
<button type="button" class="btn btn_02" id="btn_check_popbill">설정 확인</button>
<div id="popbill_check_result"></div>
</td>
</tr>
<tr>
<th scope="row">팝빌 연동신청</th>
<td>
<?php echo help('팝빌 연동신청이 필요할 경우 아래 버튼을 클릭하세요.<br>회원가입 시 연동회원으로 선택후 링크아이디 [SIRSOFT]를 넣어주세요.'); ?>
<a href="https://www.popbill.com/App/SignUp" target="_blank" class="btn_frmline">팝빌 연동신청</a>
</td>
</tr>
<tr>
<th scope="row">알림톡 프리셋 설정</th>
<td>
<a href="<?php echo G5_ADMIN_URL; ?>/alimtalkpreset.php" class="btn_frmline">환경설정 &gt; 알림톡프리셋관리</a> 에서 설정하실 수 있습니다.
</td>
</tr>
</table>
</div>
</section>
<section id="anc_cf_article_mail">
<h2 class="h2_frm">게시판 글 작성 시 메일 설정</h2>
<h2 class="h2_frm">게시판 글 작성 시 알림 설정</h2>
<?php echo $pg_anchor ?>
<div class="tbl_frm01 tbl_wrap">
<table>
<caption>게시판 글 작성 시 메일 설정</caption>
<caption>게시판 글 작성 시 알림 설정</caption>
<colgroup>
<col class="grid_4">
<col>
@ -1197,12 +1315,12 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
<section id="anc_cf_join_mail">
<h2 class="h2_frm">회원가입 시 메일 설정</h2>
<h2 class="h2_frm">회원가입 시 알림 설정</h2>
<?php echo $pg_anchor ?>
<div class="tbl_frm01 tbl_wrap">
<table>
<caption>회원가입 시 메일 설정</caption>
<caption>회원가입 시 알림 설정</caption>
<colgroup>
<col class="grid_4">
<col>
@ -1229,12 +1347,12 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
<section id="anc_cf_vote_mail">
<h2 class="h2_frm">투표 기타의견 작성 시 메일 설정</h2>
<h2 class="h2_frm">투표 기타의견 작성 시 알림 설정</h2>
<?php echo $pg_anchor ?>
<div class="tbl_frm01 tbl_wrap">
<table>
<caption>투표 기타의견 작성 시 메일 설정</caption>
<caption>투표 기타의견 작성 시 알림 설정</caption>
<colgroup>
<col class="grid_4">
<col>
@ -1526,7 +1644,6 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
</div>
</section>
<section id="anc_cf_extra">
<h2 class="h2_frm">여분필드 기본 설정</h2>
<?php echo $pg_anchor ?>
@ -1732,6 +1849,50 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
});
</script>
<!-- 카카오톡 - 팝빌 설정 확인 -->
<?php add_javascript('<script src="'.G5_JS_URL.'/kakao5.js"></script>', 1); // 카카오톡5 솔루션 js 추가 ?>
<script>
$(function() {
$('#btn_check_popbill').on('click', function() {
var $resultDiv = $('#popbill_check_result');
$resultDiv.html('<i class="fa fa-spinner fa-spin"></i> 확인 중...');
$.ajax({
url: '<?php echo G5_KAKAO5_URL;?>/ajax.check_popbill.php',
type: 'POST',
dataType: 'json',
success: function(data) {
var html = '';
if (data.error) {
html = '<div class="alert alert-danger" style="margin-top:10px;"><i class="fa fa-exclamation-triangle"></i> ' + data.error + '</div>';
} else {
html = '<div class="alert alert-success"><i class="fa fa-check-circle"></i> 팝빌이 정상적으로 설정되었습니다.</div>';
if (typeof data.balance !== 'undefined') {
html += '<div class="alert alert-info"><i class="fa fa-info-circle"></i> 잔여포인트: ' + Number(data.balance).toLocaleString() + '원';
html += ' <a href="#" id="btn_point_charge" class="btn btn_02">포인트 충전하기</a>';
html += '</div>';
}
}
$resultDiv.html(html); // 팝빌 설정 결과 출력
$('#btn_check_popbill').hide();
// 포인트 충전 팝업: [정의] openKakao5PopupFromAjax() - js/kakao5.js
var $chargeBtn = $('#btn_point_charge');
if ($chargeBtn.length) {
$chargeBtn.off('click').on('click', async function(e) {
e.preventDefault();
await openKakao5PopupFromAjax('<?php echo G5_KAKAO5_URL; ?>', 5);
});
}
},
error: function() {
$resultDiv.html('<div class="alert alert-danger"><i class="fa fa-exclamation-triangle"></i> 네트워크 오류</div>');
}
});
});
});
</script>
<?php
// 본인확인 모듈 실행권한 체크
if ($config['cf_cert_use']) {

View File

@ -141,6 +141,7 @@ $check_keys = array(
'cf_visit' => 'char',
'cf_stipulation' => 'text',
'cf_privacy' => 'text',
'cf_use_promotion' => 'int',
'cf_open_modify' => 'int',
'cf_memo_send_point' => 'int',
'cf_mobile_new_skin' => 'char',
@ -157,7 +158,13 @@ $check_keys = array(
'cf_icode_server_ip' => 'char',
'cf_captcha' => 'char',
'cf_syndi_token' => '',
'cf_syndi_except' => ''
'cf_syndi_except' => '',
'cf_kakaotalk_use' => 'char',
'cf_kakaotalk_corpnum' => 'char',
'cf_kakaotalk_sender_hp' => 'char',
'cf_popbill_userid' => 'char',
'cf_popbill_link_id' => 'char',
'cf_popbill_secretkey' => 'char'
);
for ($i = 1; $i <= 10; $i++) {
@ -300,6 +307,7 @@ $sql = " update {$g5['config_table']}
cf_mobile_page_rows = '{$_POST['cf_mobile_page_rows']}',
cf_stipulation = '{$_POST['cf_stipulation']}',
cf_privacy = '{$_POST['cf_privacy']}',
cf_use_promotion = '{$_POST['cf_use_promotion']}',
cf_open_modify = '{$_POST['cf_open_modify']}',
cf_memo_send_point = '{$_POST['cf_memo_send_point']}',
cf_mobile_new_skin = '{$_POST['cf_mobile_new_skin']}',
@ -348,6 +356,12 @@ $sql = " update {$g5['config_table']}
cf_recaptcha_secret_key = '{$_POST['cf_recaptcha_secret_key']}',
cf_payco_clientid = '{$_POST['cf_payco_clientid']}',
cf_payco_secret = '{$_POST['cf_payco_secret']}',
cf_kakaotalk_use = '{$_POST['cf_kakaotalk_use']}',
cf_kakaotalk_corpnum = '{$_POST['cf_kakaotalk_corpnum']}',
cf_kakaotalk_sender_hp = '{$_POST['cf_kakaotalk_sender_hp']}',
cf_popbill_userid = '{$_POST['cf_popbill_userid']}',
cf_popbill_link_id = '{$_POST['cf_popbill_link_id']}',
cf_popbill_secretkey = '{$_POST['cf_popbill_secretkey']}',
cf_1_subj = '{$_POST['cf_1_subj']}',
cf_2_subj = '{$_POST['cf_2_subj']}',
cf_3_subj = '{$_POST['cf_3_subj']}',

View File

@ -28,6 +28,39 @@ box-sizing: border-box;
h2{font-size: 1.083em;font-weight: bold;margin:10px 0}
#wrapper {min-height:480px}
/* admin 공통 */
/* 공통 - display none/block */
.is-hidden { display: none !important; }
.is-visible { display: block !important; }
/* 공통 - 뷰포트 (pc / mobile) 별 display none/block */
.pc-only { display: none; }
@media (min-width: 769px) { .pc-only { display: block !important; }}
.mobile-only { display: block; }
@media (min-width: 769px) { .mobile-only { display: none !important; }}
/* 공통 - 레이어 팝업 */
.popup-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.3); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); z-index: 9999; display: flex; justify-content: center; align-items: center; }
.popup-content { background: #fff; border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.15); width: 800px; overflow: hidden; }
.popup-header, .popup-footer { padding: 18px 20px; display: flex; align-items: center; }
.popup-header { justify-content: space-between; border-bottom: 1px solid #e0e0e0; }
.popup-footer { gap: 20px; border-top: 1px solid #e0e0e0;}
.popup-close-btn { background: none; border: none; color: #888; font-size: 20px; cursor: pointer; padding: 4px; display: flex; align-items: center; justify-content: center; transition: color 0.2s ease; }
.popup-close-btn:hover { color: #333; }
.popup-title { font-size: 18px; font-weight: 600; }
.popup-body { padding: 20px; max-height: 400px; overflow-y: auto; color: #333; }
.popup-footer button { background: #3d70ff; color: white; border: 1px solid #3d70ff; padding: 8px 16px; border-radius: 6px; font-weight: 600; cursor: pointer; transition: background 0.2s ease, border-color 0.2s ease; }
.popup-footer button:hover { background: #2b3d9f; border-color: #2b3d9f; }
/* 공통 - tab */
.tab-container { display: flex; flex-direction: column; width: 100%; }
.tab-header { position: relative; bottom: -1px; display: flex; }
.tab-btn { padding: 10px 14px; background: none; border: none; border-bottom: 2px solid transparent; cursor: pointer; color: inherit; font: inherit; }
.tab-btn.active { border-bottom-color: #000; font-weight: bold; }
.tab-body { width: 100%; border-top: 1px solid #ccc; }
.tab-content { padding: 16px 0; }
/* 레이아웃 */
#hd h1 {position:absolute;font-size:0;line-height:0;overflow:hidden}
#hd_top{position:fixed;top:0;left:0;width:100%;height:50px;background:#3f51b5;z-index:1000}
@ -71,6 +104,8 @@ h2{font-size: 1.083em;font-weight: bold;margin:10px 0}
#gnb .on .btn_op.menu-400{background:url(../img/menu-7.png) 50% 50% no-repeat #fff}
#gnb .gnb_li .btn_op.menu-500{background:url(../img/menu-6-1.png) 50% 50% no-repeat #ebebeb }
#gnb .on .btn_op.menu-500{background:url(../img/menu-6.png) 50% 50% no-repeat #fff}
#gnb .gnb_li .btn_op.menu-800{background:url(../img/menu-8-1.png) 50% 50% no-repeat #ebebeb }
#gnb .on .btn_op.menu-800{background:url(../img/menu-8.png) 50% 50% no-repeat #fff}
#gnb .gnb_li .btn_op.menu-900{background:url(../img/menu-4-1.png) 50% 50% no-repeat #ebebeb }
#gnb .on .btn_op.menu-900{background:url(../img/menu-4.png) 50% 50% no-repeat #fff}
#gnb .gnb_li button:hover{background-color:#f3f3f3}
@ -95,9 +130,11 @@ box-shadow: 2px 0 2px rgba(150,150,150,0.1);}
#container.container-small #container_title{padding-left:70px}
.container_wr{padding:20px}
/* 화면낭독기 사용자용 */
/* 화면낭독기 사용자용 (스크린 리더 대응) */
/* 일반적인 .blind/.sr-only 사용시에 .sound_only 사용 권장 */
#hd_login_msg {position:absolute;top:0;left:0;width:1px;height:1px;overflow:hidden}
.msg_sound_only, .sound_only {display:inline-block !important;position:absolute;top:0;left:0;margin:0 !important;padding:0 !important;width:1px !important;height:1px !important;font-size:0;line-height:0;border:0 !important;overflow:hidden !important}
.sound_only, .msg_sound_only {overflow:hidden;position:absolute;width:1px;height:1px;margin:-1px;padding:0;clip:rect(0,0,0,0)}
/* 본문 바로가기 */
#to_content a {z-index:100000;position:absolute;top:0;left:0;font-size:0;line-height:0;overflow:hidden}
#to_content a:focus, #to_content a:active {width:100%;height:70px;background:#fff;font-size:2em;font-weight:bold;text-align:center;text-decoration:none;line-height:3.1em}
@ -196,6 +233,8 @@ a.btn_submit{background:#ff4081;color:#fff}
.btn_02,a.btn_02{background:#9eacc6;color:#fff;}
.btn_03,a.btn_03{background:#3f51b5;color:#fff;}
.btn_04,a.btn_04{background:#555;color:#fff}
.btn_04:hover,a.btn_04:hover{background:#666}
.btn_frmline{display:inline-block;background:#9eacc6;color:#fff;height:35px;border:0;border-radius:5px;padding:0 10px}
a.btn_frmline{display:inline-block;background:#9eacc6;color:#fff;height:35px;line-height:33px;border-radius:5px;padding:0 10px;text-decoration:none !important}
@ -247,18 +286,14 @@ legend {position:absolute;width:0;height:0;font-size:0;line-height:0;text-indent
.anchor a {display:inline-block;padding:5px 10px;border:1px solid #c8ced1;background:#d6dde1;text-decoration:none}
.anchor .selected{background:#3f51b5}
#sort_mb {width:800px}
#sort_sodr {width:600px}
/* 하단 레이아웃 */
#ft{background:#f3f3f3;padding:0 25px;color:#777;text-align:center}
#ft p{line-height:50px;}
.scroll_top{position:fixed;bottom:10px;right:10px;width:50px;height:50px;border:0;text-align:center;background:#ddd;background:rgba(0,0,0,0.1)}
.scroll_top{position:fixed;bottom:10px;right:10px;width:50px;height:50px;border:0;text-align:center;background:#ddd;background:rgba(0,0,0,0.1);z-index:50;}
.scroll_top span.top_img{display:inline-block;width: 0; height: 0; border-left: 5px solid transparent;border-right: 5px solid transparent;
border-bottom: 5px solid black;}
.scroll_top span.top_txt{display:block}
@ -281,9 +316,59 @@ border-bottom: 5px solid black;}
.local_sch03 button{height:30px;padding:0 5px;border:0;background:#9eacc6;color:#fff;}
.local_sch03 .btn_submit{height:30px;padding:0 5px;border:0;color:#fff;}
.local_sch03 .frm_input{height:30px;border:1px solid #dcdcdc;padding:0 5px;}
/* 회원 관리 데이터 필터링 */
.member_list_data { display: flex; flex-direction: column; padding: 20px; margin: 20px 0 40px; background: #f9f9f9; border: 1px solid #f2f2f2; color: #333; }
.sch_table { display: flex; flex-direction: column; gap: 10px; font-size: 11.5px; color: #333; }
.member_list_data .sch_row { display: flex; align-items: center; gap: 12px; min-height: 30px; }
.label { min-width: 120px; font-weight: 500; white-space: nowrap; display: flex; align-items: center; }
.label label {display: flex; gap: 10px;}
.field { flex: 1; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.field input[type="text"], .field input[type="number"], .field input[type="date"], .field select { height: 30px; min-width: 100px; padding: 0 10px; font-size: 11.5px; border: 1px solid #ddd; border-radius: 8px; background: #fff; transition: border-color 0.2s ease, box-shadow 0.2s ease; }
.field input[type="text"]:focus, .field input[type="number"]:focus, .field input[type="date"]:focus, .field select:focus { border-color: #6f809a; box-shadow: 0 0 0 2px rgba(63,81,181,0.1); outline: none; }
.field input::placeholder { color: #aaa; }
.field input[type="checkbox"], .field input[type="radio"] { width: 14px; height: 14px; accent-color: #536177; }
.radio_group { display: flex; gap: 15px; align-items: center; padding: 0 10px;}
.radio_group label {display: flex; align-items: center; gap: 5px;}
.ad_range_wrap {flex: 1; padding-left: 20px;}
.ad_range_box {display: flex;}
.ad_range_box .label {width: 109px;}
.sch_notice { font-size: 11px; color: #999; }
.sch_btn { display: flex; gap: 20px; justify-content: center; margin-top: 40px; }
.sch_btn { display: flex; gap: 10px; }
.btn_reset { display: flex; align-items: center; gap: 6px; padding: 0 20px; height: 40px; background: #9eacc6; color: #fff; font-weight: 600; border: none; border-radius: 8px; cursor: pointer; transition: background 0.2s ease, transform 0.15s ease; }
.btn_reset:hover { background: #5f6e89; }
.sch_btn button:not(.btn_reset) { padding: 0 20px; height: 40px; border: 1px solid #ccd1d8; background-color: #fff; color: #444; font-weight: 600; border-radius: 8px; cursor: pointer; user-select: none; transition: border-color 0.2s ease, box-shadow 0.2s ease; box-shadow: 0 1px 2px rgba(0,0,0,0.03); }
.sch_btn button:not(.btn_reset):hover { border-color: #6f809a; box-shadow: 0 2px 4px rgba(111, 128, 154, 0.15); }
.sch_btn button:not(.btn_reset):active { box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); }
/* 회원 관리 다운로드 진행 팝업 */
.excel-download-progress p { color: #374151; }
.excel-download-progress .progress-desc { padding: 40px 0 32px; text-align: center; }
.excel-download-progress .progress-summary { margin-bottom: 6px; font-size: 16px; font-weight: 500; color: #111827; }
.excel-download-progress .progress-message { font-size: 20px; font-weight: 600; color: #3b82f6; }
.excel-download-progress .progress-error { color:red; }
.progress-spinner { display: flex; flex-direction: column; align-items: center; gap: 45px; padding: 24px 0; transition: all 0.2s ease; }
.spinner { width: 48px; height: 48px; border: 5px solid #3b82f6; border-top: 5px solid #fff; border-radius: 50%; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.loading-message { text-align: center; font-size: 14px; color: #374151; }
.excel-download-progress .progress-download-box { margin-top: 24px; background: #f9fafb; padding: 20px; border-radius: 8px; box-shadow: 0 1px 2px rgba(0,0,0,0.03); }
.excel-download-progress .progress-download-box a { display: block; width: 100%; height: auto; text-align: center; margin-top: 8px; font-weight: 600; font-size: 14px; padding: 10px 20px; background: #fff; border: 1px solid #ccd1d8; border-radius: 8px; color: #444; cursor: pointer; transition: border-color 0.2s ease, box-shadow 0.2s ease; box-shadow: 0 1px 2px rgba(0,0,0,0.03); }
.excel-download-progress .progress-download-box a:hover { border-color: #6f809a; box-shadow: 0 2px 4px rgba(111, 128, 154, 0.15); }
.excel-download-progress .progress-download-box a:active { box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); }
.field-select-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 15px; gap: 0px 10px; padding: 10px; background-color: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; color: #374151; }
.field-select-form label { display: flex; align-items: center; cursor: pointer; padding: 6px 10px; border-radius: 4px; }
.field-select-form label:hover { background-color: #f3f4f6; }
.field-select-form input[type="checkbox"] { margin-right: 8px; transform: scale(1.2); }
.field-separator { grid-column: 1 / -1; border-top: 1px solid #d1d5db; margin: 8px 0; }
.selected-fields-preview { padding: 8px; background-color: #eef2f7; border: 1px solid #d1d5db; border-radius: 6px; margin: 10px 0px; color: #1f2937; display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.selected-fields-preview strong { padding: 4px 8px; }
.selected-fields-preview .field-tag { background-color: #dbeafe; color: #1e40af; padding: 4px 8px; border-radius: 4px; }
/* 페이지 내 실행 */
.local_cmd {min-width:960px}
.local_cmd01 {margin:0 0 10px;padding:0 }
.local_cmd01 .cmd_tit {font-weight:bold}
.local_cmd01 .btn_submit {padding:3px 5px;border:1px solid #ff3061;color:#fff;font-size:0.95em;vertical-align:middle}
@ -298,7 +383,7 @@ border-bottom: 5px solid black;}
.local_desc01 {margin:10px 0 10px ;padding:10px 20px;border:1px solid #f2f2f2;background:#f9f9f9}
.local_desc01 strong {color:#ff3061}
.local_desc01 a {text-decoration:underline}
.local_desc01 a {text-decoration:underline;text-underline-offset:2px;}
.local_desc02 {margin:10px 0 ;min-width:960px} /* 주로 온라인 서식 관련 안내 내용에 사용 */
.local_desc02 p {padding:0;line-height:1.8em}
@ -401,6 +486,7 @@ tfoot th {}
.mb_leave_msg {color:#b6b6b6}
.mb_intercept_msg {color:#ff0000}
#point_mng {margin-top:50px}
.ad_agree_log {max-height: 150px !important;}
/* 게시판추가/수정 */
#anc_bo_extra .td_grpset label {width:auto}
@ -504,6 +590,7 @@ td.td_grpset {width:160px;border-left:1px solid #e9ecee;text-align:center}
.td_time{text-align:center;width:130px}
.td_center{text-align:center;}
.td_type{width:120px}
.td_consent{width:200px}
.td_mng_s{width:60px}
.td_mng_m{width:100px}
@ -1134,3 +1221,24 @@ input[type="text"]{max-width:200px}
/* Styles */
input[type="text"]{max-width:200px}
}
/* 쇼핑몰관리 > 알림톡프리셋관리 */
.template_preview {display:none;z-index:10;position:absolute;padding:20px;width:400px;min-height:300px;max-height:300px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;text-align: left;}
.template_preview_txt {padding:10px;width:100%;height:300px;border:1px solid #696c71;background:#f7f7f7;overflow-y:scroll;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
.btn_template_preview_open {padding:5px 10px;width:77px;height:30px;line-height:10px;border:0;border-radius:5px;background:#484848;color:#fff}
.btn_template_preview_close {margin:0;padding:0;width:100%;height:40px;line-height:40px;border:0;background:#484848;color:#fff}
.variable_table {overflow:hidden;max-height:0;transition:max-height 0.7s}
.variable_table.is-visible {max-height:1000px !important;}
.variable_table .tbl_head01 tbody td {background-color: #fff;}
.preset-toggle{position:relative;display:inline-block;width:50px;height:24px}
.preset-toggle input{opacity:0;width:0;height:0}
.preset-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background:#ccc;transition:.4s;border-radius:24px}
.preset-slider:before{position:absolute;content:"";height:18px;width:18px;left:3px;bottom:3px;background:#fff;transition:.4s;border-radius:50%}
input:checked+.preset-slider{background:#4CAF50}
input:checked+.preset-slider:before{transform:translateX(26px)}
/* 친구톡 전송 관련 */
.kakao-send-svg { width: 16px; height: 16px; fill: currentColor; margin-bottom: -3px; }
.kakao-setting-btn { height: auto; padding: 7px 12px; background: #3d70ff; color: white; border: none; border-radius: 6px; font-weight: 600; min-width: 110px;}
.kakao-setting-btn:hover { background: #2c5bd3; }

View File

@ -289,6 +289,166 @@ if($g5['sms5_prefix'] != 'sms5_' && sql_num_rows(sql_query("show tables like 'sm
$is_check = true;
}
// 카카오톡 프리셋 테이블
if( isset($g5['kakao5_preset_table']) && !sql_query(" DESC {$g5['kakao5_preset_table']} ", false)) {
sql_query(" CREATE TABLE IF NOT EXISTS `{$g5['kakao5_preset_table']}` (
`kp_id` int(11) NOT NULL AUTO_INCREMENT,
`kp_type` varchar(20) NOT NULL DEFAULT '',
`kp_category` varchar(20) NOT NULL DEFAULT '',
`kp_preset_code` varchar(100) NOT NULL DEFAULT '',
`kp_preset_name` varchar(100) NOT NULL DEFAULT '',
`kp_template_name` varchar(100) NOT NULL DEFAULT '',
`kp_alt_send` varchar(100) NOT NULL DEFAULT '1',
`kp_active` tinyint(1) NOT NULL DEFAULT '1',
`kp_created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`kp_updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`kp_id`)
) ", true);
// 기본 프리셋 데이터 추가
sql_query("INSERT INTO `{$g5['kakao5_preset_table']}`
(`kp_type`, `kp_category`, `kp_preset_code`, `kp_preset_name`, `kp_template_name`, `kp_alt_send`, `kp_active`, `kp_created_at`, `kp_updated_at`)
VALUES
('회원', '회원', 'CU-MB01', '회원가입완료', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('최고관리자', '회원', 'AD-MB01', '회원가입완료', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('작성자', '게시판', 'CU-BO01', '새 게시글 작성', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('최고관리자', '게시판', 'AD-BO01', '새 게시글 작성', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('그룹관리자', '게시판', 'AD-BO02', '새 게시글 작성', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('게시판관리자', '게시판', 'AD-BO03', '새 게시글 작성', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('작성자', '게시판', 'CU-BO02', '새 댓글 작성', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('댓글 작성자', '게시판', 'CU-BO03', '새 댓글 작성', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('답변글 작성자', '게시판', 'CU-BO04', '답변글 작성', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('최고관리자', '투표', 'AD-VO01', '기타의견 작성', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-OR01', '주문 완료', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('최고관리자', '쇼핑몰', 'AD-OR01', '주문 완료', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-OR02', '무통장입금 주문 완료', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('최고관리자', '쇼핑몰', 'AD-OR02', '무통장입금 주문 완료', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-OR03', '무통장입금 완료', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('최고관리자', '쇼핑몰', 'AD-OR03', '무통장입금 완료', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-OR04', '(주문자)주문 취소', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('최고관리자', '쇼핑몰', 'AD-OR04', '(주문자)주문 취소', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-OR05', '(관리자)주문 취소', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('최고관리자', '쇼핑몰', 'AD-OR05', '(관리자)주문 취소', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-OR06', '반품', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-OR07', '품절', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-DE01', '배송 준비', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-DE02', '배송중', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('주문자', '쇼핑몰', 'CU-DE03', '배송 완료', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('요청자', '쇼핑몰', 'CU-ST01', '재입고알림', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('문의자', '1:1문의', 'CU-IQ01', '문의 등록', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('최고관리자', '1:1문의', 'AD-IQ01', '문의 등록', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('문의자', '1:1문의', 'CU-IQ02', '답변 등록', '', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
", true);
$is_check = true;
}
// 카카오톡 프리셋 전송내역 테이블
if( isset($g5['kakao5_preset_history_table']) && !sql_query(" DESC {$g5['kakao5_preset_history_table']} ", false)) {
sql_query(" CREATE TABLE IF NOT EXISTS `{$g5['kakao5_preset_history_table']}` (
`ph_id` int(11) NOT NULL AUTO_INCREMENT,
`kp_id` int(11) NOT NULL DEFAULT '0',
`mb_id` varchar(20) NOT NULL DEFAULT '',
`ph_rcvnm` varchar(100) NOT NULL DEFAULT '',
`ph_rcv` varchar(100) NOT NULL DEFAULT '',
`ph_template_code` varchar(100) NOT NULL DEFAULT '',
`ph_alt_send` varchar(100) NOT NULL DEFAULT '',
`ph_request_num` varchar(100) NOT NULL DEFAULT '',
`ph_receipt_num` varchar(100) NOT NULL DEFAULT '',
`ph_send_datetime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`ph_state` tinyint(1) NOT NULL DEFAULT '0',
`ph_log` text NOT NULL,
PRIMARY KEY (`ph_id`),
KEY `kp_id` (`kp_id`),
KEY `mb_id` (`mb_id`)
) ", true);
$is_check = true;
}
// 카카오톡 설정 필드 추가
if (!isset($config['cf_kakaotalk_use'])) {
sql_query(
" ALTER TABLE `{$g5['config_table']}`
ADD `cf_kakaotalk_use` varchar(50) NOT NULL DEFAULT '' AFTER `cf_recaptcha_secret_key`,
ADD `cf_kakaotalk_corpnum` varchar(50) NOT NULL DEFAULT '' AFTER `cf_kakaotalk_use`,
ADD `cf_kakaotalk_sender_hp` varchar(50) NOT NULL DEFAULT '' AFTER `cf_kakaotalk_corpnum`,
ADD `cf_popbill_userid` varchar(100) NOT NULL DEFAULT '' AFTER `cf_kakaotalk_sender_hp`,
ADD `cf_popbill_link_id` varchar(100) NOT NULL DEFAULT '' AFTER `cf_popbill_userid`,
ADD `cf_popbill_secretkey` varchar(255) NOT NULL DEFAULT '' AFTER `cf_popbill_link_id` ",
true
);
$is_check = true;
}
// 광고성 정보 수신 동의 사용 필드 추가
if (!isset($config['cf_use_promotion'])) {
sql_query(
" ALTER TABLE `{$g5['config_table']}`
ADD `cf_use_promotion` tinyint(1) NOT NULL DEFAULT '0' AFTER `cf_privacy` ",
true
);
$is_check = true;
}
// 광고성 정보 수신 동의 여부 필드 추가 + 메일 / SMS 수신 일자 추가
if (!isset($member['mb_marketing_agree'])) {
sql_query(
" ALTER TABLE `{$g5['member_table']}`
ADD `mb_marketing_agree` tinyint(1) NOT NULL DEFAULT '0' AFTER `mb_scrap_cnt`,
ADD `mb_marketing_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER `mb_marketing_agree`,
ADD `mb_thirdparty_agree` tinyint(1) NOT NULL DEFAULT '0' AFTER `mb_marketing_date`,
ADD `mb_thirdparty_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER `mb_thirdparty_agree`,
ADD `mb_agree_log` TEXT NOT NULL AFTER `mb_thirdparty_date`,
ADD `mb_mailling_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER `mb_mailling`,
ADD `mb_sms_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' AFTER `mb_sms` ",
true
);
$is_check = true;
}
// 게시판 설정 - SMS/알림톡 사용 여부 추가
if(!sql_query(" select bo_use_kakaotalk from {$g5['board_table']} limit 1", false)) {
sql_query(
" ALTER TABLE `{$g5['board_table']}`
ADD `bo_use_kakaotalk` VARCHAR(50) NOT NULL DEFAULT '' AFTER `bo_use_email` ",
true
);
$is_check = true;
}
// 게시판 알림 설정 필드 추가
if (!isset($member['mb_board_post'])) {
sql_query(
" ALTER TABLE `{$g5['member_table']}`
ADD `mb_board_post` tinyint(1) NOT NULL DEFAULT '0' AFTER `mb_agree_log`,
ADD `mb_board_reply` tinyint(1) NOT NULL DEFAULT '0' AFTER `mb_board_post`,
ADD `mb_board_comment` tinyint(1) NOT NULL DEFAULT '0' AFTER `mb_board_reply`,
ADD `mb_board_recomment` tinyint(1) NOT NULL DEFAULT '0' AFTER `mb_board_comment` ",
true
);
$is_check = true;
}
// 재입고 알림 - 채널 구분 (1=SMS, 2=알림톡)
if(sql_query(" DESC {$g5['g5_shop_item_stocksms_table']} ", false) && !sql_query(" select ss_channel from {$g5['g5_shop_item_stocksms_table']} limit 1", false)) {
sql_query(
" ALTER TABLE `{$g5['g5_shop_item_stocksms_table']}`
ADD `ss_channel` tinyint(4) NOT NULL DEFAULT '1' AFTER `ss_ip` ",
true
);
$is_check = true;
}
$is_check = run_replace('admin_dbupgrade', $is_check);
$db_upgrade_msg = $is_check ? 'DB 업그레이드가 완료되었습니다.' : '더 이상 업그레이드 할 내용이 없습니다.<br>현재 DB 업그레이드가 완료된 상태입니다.';

BIN
adm/img/svc_btn_07.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -52,8 +52,13 @@ if ($w == '') {
$sound_only = '<strong class="sound_only">필수</strong>';
$mb['mb_mailling'] = 1;
$mb['mb_sms'] = 1;
$mb['mb_open'] = 1;
$mb['mb_level'] = $config['cf_register_level'];
$mb['mb_board_post'] = 1;
$mb['mb_board_reply'] = 1;
$mb['mb_board_comment'] = 1;
$mb['mb_board_recomment'] = 1;
$html_title = '추가';
} elseif ($w == 'u') {
$mb = get_member($mb_id);
@ -139,6 +144,27 @@ $mb_sms_no = !$mb['mb_sms'] ? 'checked="checked"' : '';
$mb_open_yes = $mb['mb_open'] ? 'checked="checked"' : '';
$mb_open_no = !$mb['mb_open'] ? 'checked="checked"' : '';
// 마케팅 목적의 개인정보 수집 및 이용
$mb_marketing_agree_yes = $mb['mb_marketing_agree'] ? 'checked="checked"' : '';
$mb_marketing_agree_no = !$mb['mb_marketing_agree'] ? 'checked="checked"' : '';
// 개인정보 제3자 제공 동의
$mb_thirdparty_agree_yes = $mb['mb_thirdparty_agree'] ? 'checked="checked"' : '';
$mb_thirdparty_agree_no = !$mb['mb_thirdparty_agree'] ? 'checked="checked"' : '';
// 알림 설정 (전용 컬럼 사용)
$mb_board_post_yes = !empty($mb['mb_board_post']) ? 'checked="checked"' : '';
$mb_board_post_no = empty($mb['mb_board_post']) ? 'checked="checked"' : '';
$mb_board_reply_yes = !empty($mb['mb_board_reply']) ? 'checked="checked"' : '';
$mb_board_reply_no = empty($mb['mb_board_reply']) ? 'checked="checked"' : '';
$mb_board_comment_yes = !empty($mb['mb_board_comment']) ? 'checked="checked"' : '';
$mb_board_comment_no = empty($mb['mb_board_comment']) ? 'checked="checked"' : '';
$mb_board_recomment_yes = !empty($mb['mb_board_recomment']) ? 'checked="checked"' : '';
$mb_board_recomment_no = empty($mb['mb_board_recomment']) ? 'checked="checked"' : '';
if (isset($mb['mb_certify'])) {
// 날짜시간형이라면 drop 시킴
if (preg_match("/-/", $mb['mb_certify'])) {
@ -354,21 +380,64 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
</td>
</tr>
<tr>
<th scope="row">메일 수신</th>
<th scope="row">광고성 이메일 수신</th>
<td>
<input type="radio" name="mb_mailling" value="1" id="mb_mailling_yes" <?php echo $mb_mailling_yes; ?>>
<label for="mb_mailling_yes">예</label>
<input type="radio" name="mb_mailling" value="0" id="mb_mailling_no" <?php echo $mb_mailling_no; ?>>
<label for="mb_mailling_no">아니오</label>
<?php if($w == "u" && $mb['mb_mailling_date'] != "0000-00-00 00:00:00"){
echo $mb['mb_mailling'] == 1 ? "<br>(동의 일자: ".$mb['mb_mailling_date'].")" : '';
} ?>
</td>
<th scope="row"><label for="mb_sms_yes">SMS 수신</label></th>
<th scope="row"><label for="mb_sms_yes">광고성 SMS/카카오톡 수신</label></th>
<td>
<input type="radio" name="mb_sms" value="1" id="mb_sms_yes" <?php echo $mb_sms_yes; ?>>
<label for="mb_sms_yes">예</label>
<input type="radio" name="mb_sms" value="0" id="mb_sms_no" <?php echo $mb_sms_no; ?>>
<label for="mb_sms_no">아니오</label>
<?php if($w == "u" && $mb['mb_sms_date'] != "0000-00-00 00:00:00"){
echo $mb['mb_sms'] == 1 ? "<br>(동의 일자: ".$mb['mb_sms_date'].")" : '';
} ?>
</td>
</tr>
<tr>
<th scope="row">마케팅 목적의<br>개인정보 수집 및 이용</th>
<td>
<input type="radio" name="mb_marketing_agree" value="1" id="mb_marketing_agree_yes" <?php echo $mb_marketing_agree_yes; ?>>
<label for="mb_marketing_agree_yes">예</label>
<input type="radio" name="mb_marketing_agree" value="0" id="mb_marketing_agree_no" <?php echo $mb_marketing_agree_no; ?>>
<label for="mb_marketing_agree_no">아니오</label>
<?php if($w == "u" && $mb['mb_marketing_date'] != "0000-00-00 00:00:00"){
echo $mb['mb_marketing_agree'] == 1 ? "<br>(동의 일자: ".$mb['mb_marketing_date'].")" : '';
} ?>
</td>
<th scope="row"><label for="mb_sms_yes">개인정보 제3자 제공</label></th>
<td>
<input type="radio" name="mb_thirdparty_agree" value="1" id="mb_thirdparty_agree_yes" <?php echo $mb_thirdparty_agree_yes; ?>>
<label for="mb_thirdparty_agree_yes">예</label>
<input type="radio" name="mb_thirdparty_agree" value="0" id="mb_thirdparty_agree_no" <?php echo $mb_thirdparty_agree_no; ?>>
<label for="mb_thirdparty_agree_no">아니오</label>
<?php if($w == "u" && $mb['mb_thirdparty_date'] != "0000-00-00 00:00:00"){
echo $mb['mb_thirdparty_agree'] == 1 ? "<br>(동의 일자: ".$mb['mb_thirdparty_date'].")" : '';
} ?>
</td>
</tr>
<?php if($w == "u"){?>
<tr>
<th scope="row">약관동의 변경내역</th>
<td colspan="3">
<section id="sodr_request_log_wrap" class="ad_agree_log">
<div>
<?php echo conv_content($mb['mb_agree_log'], 0); ?>
</div>
</section>
</td>
</tr>
<?php } ?>
<tr>
<th scope="row">정보 공개</th>
<td colspan="3">
@ -376,6 +445,9 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<label for="mb_open_yes">예</label>
<input type="radio" name="mb_open" value="0" id="mb_open_no" <?php echo $mb_open_no; ?>>
<label for="mb_open_no">아니오</label>
<?php if($w == "u" && $mb['mb_open_date'] != "0000-00-00 00:00:00"){
echo $mb['mb_open'] == 1 ? "<br>(동의 일자: ".$mb['mb_open_date'].")" : '';
} ?>
</td>
</tr>
<tr>
@ -565,6 +637,42 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
run_event('admin_member_form_add', $mb, $w, 'table');
?>
<tr>
<th scope="row">게시글 작성 완료 알림</th>
<td>
<input type="radio" name="mb_board_post" value="1" id="mb_board_post_yes" <?php echo !empty($mb['mb_board_post']) ? 'checked' : ''; ?>>
<label for="mb_board_post_yes">예</label>
<input type="radio" name="mb_board_post" value="0" id="mb_board_post_no" <?php echo empty($mb['mb_board_post']) ? 'checked' : ''; ?>>
<label for="mb_board_post_no">아니오</label>
</td>
<th scope="row">게시글 답변 알림</th>
<td>
<input type="radio" name="mb_board_reply" value="1" id="mb_board_reply_yes" <?php echo !empty($mb['mb_board_reply']) ? 'checked' : ''; ?>>
<label for="mb_board_reply_yes">예</label>
<input type="radio" name="mb_board_reply" value="0" id="mb_board_reply_no" <?php echo empty($mb['mb_board_reply']) ? 'checked' : ''; ?>>
<label for="mb_board_reply_no">아니오</label>
</td>
</tr>
<tr>
<th scope="row">댓글 알림</th>
<td>
<input type="radio" name="mb_board_comment" value="1" id="mb_board_comment_yes" <?php echo !empty($mb['mb_board_comment']) ? 'checked' : ''; ?>>
<label for="mb_board_comment_yes">예</label>
<input type="radio" name="mb_board_comment" value="0" id="mb_board_comment_no" <?php echo empty($mb['mb_board_comment']) ? 'checked' : ''; ?>>
<label for="mb_board_comment_no">아니오</label>
</td>
<th scope="row">대댓글 알림</th>
<td>
<input type="radio" name="mb_board_recomment" value="1" id="mb_board_recomment_yes" <?php echo !empty($mb['mb_board_recomment']) ? 'checked' : ''; ?>>
<label for="mb_board_recomment_yes">예</label>
<input type="radio" name="mb_board_recomment" value="0" id="mb_board_recomment_no" <?php echo empty($mb['mb_board_recomment']) ? 'checked' : ''; ?>>
<label for="mb_board_recomment_no">아니오</label>
</td>
</tr>
<?php for ($i = 1; $i <= 10; $i++) { ?>
<tr>
<th scope="row"><label for="mb_<?php echo $i ?>">여분 필드 <?php echo $i ?></label></th>

View File

@ -18,6 +18,16 @@ $mb_certify_case = isset($_POST['mb_certify_case']) ? preg_replace('/[^0-9a-z_]/
$mb_certify = isset($_POST['mb_certify']) ? preg_replace('/[^0-9a-z_]/i', '', $_POST['mb_certify']) : '';
$mb_zip = isset($_POST['mb_zip']) ? preg_replace('/[^0-9a-z_]/i', '', $_POST['mb_zip']) : '';
// 광고성 정보 수신
$mb_marketing_agree = isset($_POST['mb_marketing_agree']) ? clean_xss_tags($_POST['mb_marketing_agree'], 1, 1) : '0';
$mb_thirdparty_agree = isset($_POST['mb_thirdparty_agree']) ? clean_xss_tags($_POST['mb_thirdparty_agree'], 1, 1) : '0';
// 게시판알림 설정
$mb_board_post = isset($_POST['mb_board_post']) ? (int)$_POST['mb_board_post'] : 0;
$mb_board_reply = isset($_POST['mb_board_reply']) ? (int)$_POST['mb_board_reply'] : 0;
$mb_board_comment = isset($_POST['mb_board_comment']) ? (int)$_POST['mb_board_comment'] : 0;
$mb_board_recomment = isset($_POST['mb_board_recomment']) ? (int)$_POST['mb_board_recomment'] : 0;
// 관리자가 자동등록방지를 사용해야 할 경우 ( 회원의 비밀번호 변경시 캡챠를 체크한다 )
if ($mb_password) {
include_once(G5_CAPTCHA_PATH . '/captcha.lib.php');
@ -86,8 +96,6 @@ foreach ($check_keys as $key) {
}
}
$mb_memo = isset($_POST['mb_memo']) ? $_POST['mb_memo'] : '';
$sql_common = " mb_name = '{$posts['mb_name']}',
mb_nick = '{$mb_nick}',
mb_email = '{$mb_email}',
@ -109,8 +117,15 @@ $sql_common = " mb_name = '{$posts['mb_name']}',
mb_mailling = '{$posts['mb_mailling']}',
mb_sms = '{$posts['mb_sms']}',
mb_open = '{$posts['mb_open']}',
mb_open_date = '".G5_TIME_YMDHIS."',
mb_profile = '{$posts['mb_profile']}',
mb_level = '{$posts['mb_level']}',
mb_marketing_agree = '{$mb_marketing_agree}',
mb_thirdparty_agree = '{$mb_thirdparty_agree}',
mb_board_post = '{$mb_board_post}',
mb_board_reply = '{$mb_board_reply}',
mb_board_comment = '{$mb_board_comment}',
mb_board_recomment = '{$mb_board_recomment}',
mb_1 = '{$posts['mb_1']}',
mb_2 = '{$posts['mb_2']}',
mb_3 = '{$posts['mb_3']}',
@ -142,6 +157,36 @@ if ($w == '') {
alert('이미 존재하는 이메일입니다.\\n : ' . $row['mb_id'] . '\\n이름 : ' . $row['mb_name'] . '\\n닉네임 : ' . $row['mb_nick'] . '\\n메일 : ' . $row['mb_email']);
}
$agree_items = [];
// 마케팅 목적의 개인정보 수집 및 이용
if ($mb_marketing_agree == 1) {
$sql_common .= " , mb_marketing_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "마케팅 목적의 개인정보 수집 및 이용(동의)";
}
// 광고성 이메일 수신
if ($mb_mailling == 1) {
$sql_common .= " , mb_mailling_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "광고성 이메일 수신(동의)";
}
// 광고성 SMS/카카오톡 수신
if ($mb_sms == 1) {
$sql_common .= " , mb_sms_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "광고성 SMS/카카오톡 수신(동의)";
}
// 개인정보 제3자 제공
if ($mb_thirdparty_agree == 1) {
$sql_common .= " , mb_thirdparty_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "개인정보 제3자 제공(동의)";
}
// 동의 로그 추가
if (!empty($agree_items)) {
$agree_log = "[".G5_TIME_YMDHIS.", 관리자 회원추가] " . implode(' | ', $agree_items) . "\n";
$sql_common .= " , mb_agree_log = CONCAT('{$agree_log}', IFNULL(mb_agree_log, ''))";
}
sql_query(" insert into {$g5['member_table']} set mb_id = '{$mb_id}', mb_password = '" . get_encrypt_string($mb_password) . "', mb_datetime = '" . G5_TIME_YMDHIS . "', mb_ip = '{$_SERVER['REMOTE_ADDR']}', mb_email_certify = '" . G5_TIME_YMDHIS . "', {$sql_common} ");
} elseif ($w == 'u') {
$mb = get_member($mb_id);
@ -193,10 +238,54 @@ if ($w == '') {
$sql_certify = "";
}
// 현재 데이터 조회
$row = sql_fetch("select * from {$g5['member_table']} where mb_id = '{$mb_id}' ");
$agree_items = [];
// 마케팅 목적의 개인정보 수집 및 이용
$sql_marketing_date = "";
if ($row['mb_marketing_agree'] !== $mb_marketing_agree) {
$sql_marketing_date .= " , mb_marketing_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "마케팅 목적의 개인정보 수집 및 이용(" . ($mb_marketing_agree == 1 ? "동의" : "철회") . ")";
}
// 광고성 이메일 수신
$sql_mailling_date = "";
if ($row['mb_mailling'] !== $mb_mailling) {
$sql_mailling_date .= " , mb_mailling_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "광고성 이메일 수신(" . ($mb_mailling == 1 ? "동의" : "철회") . ")";
}
// 광고성 SMS/카카오톡 수신
$sql_sms_date = "";
if ($row['mb_sms'] !== $mb_sms) {
$sql_sms_date .= " , mb_sms_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "광고성 SMS/카카오톡 수신(" . ($mb_sms == 1 ? "동의" : "철회") . ")";
}
// 개인정보 제3자 제공
$sql_thirdparty_date = "";
if ($row['mb_thirdparty_agree'] !== $mb_thirdparty_agree) {
$sql_thirdparty_date .= " , mb_thirdparty_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "개인정보 제3자 제공(" . ($mb_thirdparty_agree == 1 ? "동의" : "철회") . ")";
}
// 동의 로그 추가
$sql_agree_log = "";
if (!empty($agree_items)) {
$agree_log = "[".G5_TIME_YMDHIS.", 관리자 회원수정] " . implode(' | ', $agree_items) . "\n";
$sql_agree_log .= " , mb_agree_log = CONCAT('{$agree_log}', IFNULL(mb_agree_log, ''))";
}
$sql = " update {$g5['member_table']}
set {$sql_common}
{$sql_password}
{$sql_certify}
{$sql_mailling_date}
{$sql_sms_date}
{$sql_marketing_date}
{$sql_thirdparty_date}
{$sql_agree_log}
where mb_id = '{$mb_id}' ";
sql_query($sql);
} else {

View File

@ -127,7 +127,7 @@ $colspan = 16;
<th scope="col" rowspan="2" id="mb_list_cert"><?php echo subject_sort_link('mb_certify', '', 'desc') ?>본인확인</a></th>
<th scope="col" id="mb_list_mailc"><?php echo subject_sort_link('mb_email_certify', '', 'desc') ?>메일인증</a></th>
<th scope="col" id="mb_list_open"><?php echo subject_sort_link('mb_open', '', 'desc') ?>정보공개</a></th>
<th scope="col" id="mb_list_mailr"><?php echo subject_sort_link('mb_mailling', '', 'desc') ?>메일수신</a></th>
<th scope="col" id="mb_list_mailr"><?php echo subject_sort_link('mb_mailling', '', 'desc') ?>광고성이메일수신</a></th>
<th scope="col" id="mb_list_auth">상태</th>
<th scope="col" id="mb_list_mobile">휴대폰</th>
<th scope="col" id="mb_list_lastcall"><?php echo subject_sort_link('mb_today_login', '', 'desc') ?>최종접속</a></th>
@ -137,7 +137,7 @@ $colspan = 16;
<tr>
<th scope="col" id="mb_list_name"><?php echo subject_sort_link('mb_name') ?>이름</a></th>
<th scope="col" id="mb_list_nick"><?php echo subject_sort_link('mb_nick') ?>닉네임</a></th>
<th scope="col" id="mb_list_sms"><?php echo subject_sort_link('mb_sms', '', 'desc') ?>SMS수신</a></th>
<th scope="col" id="mb_list_sms"><?php echo subject_sort_link('mb_sms', '', 'desc') ?>광고성SMS/카카오톡수신</a></th>
<th scope="col" id="mb_list_adultc"><?php echo subject_sort_link('mb_adult', '', 'desc') ?>성인인증</a></th>
<th scope="col" id="mb_list_auth"><?php echo subject_sort_link('mb_intercept_date', '', 'desc') ?>접근차단</a></th>
<th scope="col" id="mb_list_deny"><?php echo subject_sort_link('mb_level', '', 'desc') ?>권한</a></th>
@ -252,14 +252,15 @@ $colspan = 16;
<input type="radio" name="mb_certify[<?php echo $i; ?>]" value="ipin" id="mb_certify_ipin_<?php echo $i; ?>" <?php echo $row['mb_certify'] == 'ipin' ? 'checked' : ''; ?>>
<label for="mb_certify_ipin_<?php echo $i; ?>">아이핀</label>
</td>
<td headers="mb_list_mailc"><?php echo preg_match('/[1-9]/', $row['mb_email_certify']) ? '<span class="txt_true">Yes</span>' : '<span class="txt_false">No</span>'; ?></td>
<td headers="mb_list_open">
<td headers="mb_list_mailc" class="td_consent"><?php echo preg_match('/[1-9]/', $row['mb_email_certify']) ? '<span class="txt_true">Yes</span>' : '<span class="txt_false">No</span>'; ?></td>
<td headers="mb_list_open" class="td_consent">
<label for="mb_open_<?php echo $i; ?>" class="sound_only">정보공개</label>
<input type="checkbox" name="mb_open[<?php echo $i; ?>]" <?php echo $row['mb_open'] ? 'checked' : ''; ?> value="1" id="mb_open_<?php echo $i; ?>">
</td>
<td headers="mb_list_mailr">
<td headers="mb_list_mailr" class="td_consent">
<label for="mb_mailling_<?php echo $i; ?>" class="sound_only">메일수신</label>
<input type="checkbox" name="mb_mailling[<?php echo $i; ?>]" <?php echo $row['mb_mailling'] ? 'checked' : ''; ?> value="1" id="mb_mailling_<?php echo $i; ?>">
<input type="hidden" name="mb_mailling_default[<?php echo $i; ?>]" value="<?php echo $row['mb_mailling'] ?? '0'; ?> " id="mb_mailling_default_<?php echo $i; ?>">
</td>
<td headers="mb_list_auth" class="td_mbstat">
<?php
@ -284,6 +285,7 @@ $colspan = 16;
<td headers="mb_list_sms">
<label for="mb_sms_<?php echo $i; ?>" class="sound_only">SMS수신</label>
<input type="checkbox" name="mb_sms[<?php echo $i; ?>]" <?php echo $row['mb_sms'] ? 'checked' : ''; ?> value="1" id="mb_sms_<?php echo $i; ?>">
<input type="hidden" name="mb_sms_default[<?php echo $i; ?>]" value="<?php echo $row['mb_sms'] ?? '0'; ?> " id="mb_sms_default_<?php echo $i; ?>">
</td>
<td headers="mb_list_adultc">
<label for="mb_adult_<?php echo $i; ?>" class="sound_only">성인인증</label>

View File

@ -0,0 +1,289 @@
<?php
/*************************************************************************
**
** 내보내기 관련 상수 정의
**
*************************************************************************/
define('MEMBER_EXPORT_PAGE_SIZE', 10000); // 파일당 처리할 회원 수
define('MEMBER_EXPORT_MAX_SIZE', 300000); // 최대 처리할 회원 수
define('MEMBER_BASE_DIR', "member_list"); // 엑셀 베이스 폴더
define('MEMBER_BASE_DATE', date('YmdHis')); // 폴더/파일명용 날짜
define('MEMBER_EXPORT_DIR', G5_DATA_PATH . "/" . MEMBER_BASE_DIR . "/" . MEMBER_BASE_DATE); // 엑셀 파일 저장 경로
define('MEMBER_LOG_DIR', G5_DATA_PATH . "/" . MEMBER_BASE_DIR . "/" . "log"); // 로그 파일 저장 경로
/*************************************************************************
**
** 공통 함수 정의
**
*************************************************************************/
/**
* 검색 옵션 설정
*/
function get_export_config($type = null)
{
$config = [
'sfl_list' => [
'mb_id'=>'아이디',
'mb_name'=>'이름',
'mb_nick'=>'닉네임',
'mb_email'=>'이메일',
'mb_tel'=>'전화번호',
'mb_hp'=>'휴대폰번호',
'mb_addr1'=>'주소'
],
'point_cond_map' => [
'gte'=>'≥',
'lte'=>'≤',
'eq'=>'='
],
'intercept_list' => [
'exclude'=>'차단회원 제외',
'only'=>'차단회원만'
],
'ad_range_list' => [
'all' => '수신동의 회원 전체',
'mailling_only' => '이메일 수신동의 회원만',
'sms_only' => 'SMS/카카오톡 수신동의 회원만',
'month_confirm' => date('m월').' 수신동의 확인 대상만',
'custom_period' => '수신동의 기간 직접 입력'
],
];
return $type ? ($config[$type] ?? []) : $config;
}
/**
* 파라미터 수집 및 유효성 검사
*/
function get_member_export_params()
{
// 친구톡 양식 - 엑셀 양식에 포함할 항목
$fieldArray = array_map('trim', explode(',', $_GET['fields'] ?? ''));
$vars = [];
foreach ($fieldArray as $index => $field) {
if(!empty($field)){
$vars['var' . ($index + 1)] = $field;
}
}
$params = [
'page' => 1,
'formatType' => (int)($_GET['formatType'] ?? 1),
'use_stx' => $_GET['use_stx'] ?? 0,
'stx_cond' => clean_xss_tags($_GET['stx_cond'] ?? 'like'),
'sfl' => clean_xss_tags($_GET['sfl'] ?? ''),
'stx' => clean_xss_tags($_GET['stx'] ?? ''),
'use_level' => $_GET['use_level'] ?? 0,
'level_start' => (int)($_GET['level_start'] ?? 1),
'level_end' => (int)($_GET['level_end'] ?? 10),
'use_date' => $_GET['use_date'] ?? 0,
'date_start' => clean_xss_tags($_GET['date_start'] ?? ''),
'date_end' => clean_xss_tags($_GET['date_end'] ?? ''),
'use_point' => $_GET['use_point'] ?? 0,
'point' => $_GET['point'] ?? '',
'point_cond' => $_GET['point_cond'] ?? 'gte',
'use_hp_exist' => $_GET['use_hp_exist'] ?? 0,
'ad_range_only' => $_GET['ad_range_only'] ?? 0,
'ad_range_type' => clean_xss_tags($_GET['ad_range_type'] ?? 'all'),
'ad_mailling' => $_GET['ad_mailling'] ?? 0,
'ad_sms' => $_GET['ad_sms'] ?? 0,
'agree_date_start' => clean_xss_tags($_GET['agree_date_start'] ?? ''),
'agree_date_end' => clean_xss_tags($_GET['agree_date_end'] ?? ''),
'use_intercept' => $_GET['use_intercept'] ?? 0,
'intercept' => clean_xss_tags($_GET['intercept'] ?? 'exclude'),
'vars' => $vars,
];
// 레벨 범위 검증
if ($params['level_start'] > $params['level_end']) {
[$params['level_start'] , $params['level_end']] = [$params['level_end'], $params['level_start']];
}
// 가입기간 - 날짜 범위 검증
if ($params['use_date'] && $params['date_start'] && $params['date_end']) {
if ($params['date_start'] > $params['date_end']) {
[$params['date_start'] , $params['date_end']] = [$params['date_end'], $params['date_start']];
}
}
// 수신동의기간 - 날짜 범위 검증
if ($params['ad_range_type'] == 'custom_period' && $params['agree_date_start'] && $params['agree_date_end']) {
if ($params['agree_date_start'] > $params['agree_date_end']) {
[$params['agree_date_start'] , $params['agree_date_end']] = [$params['agree_date_end'], $params['agree_date_start']];
}
}
return $params;
}
/**
* 전체 데이터 개수 조회
*/
function member_export_get_total_count($params)
{
global $g5;
$where = member_export_build_where($params);
$sql = "SELECT COUNT(*) as cnt FROM {$g5['member_table']} {$where}";
$result = sql_query($sql);
if (!$result) {
throw new Exception("데이터 조회에 실패하였습니다. 다시 시도해주세요.");
}
$row = sql_fetch_array($result);
return (int)$row['cnt'];
}
/**
* WHERE 조건절 생성
*/
function member_export_build_where($params)
{
global $config;
$conditions = [];
// 기본 조건 - 탈퇴하지 않은 사용자
$conditions[] = "mb_leave_date = ''";
// 검색어 조건 (sql_escape_string 사용으로 보안 강화)
if (!empty($params['use_stx']) && $params['use_stx'] === '1') {
$sfl_list = get_export_config('sfl_list');
$sfl = in_array($params['sfl'], array_keys($sfl_list)) ? $params['sfl'] : '';
$stx = sql_escape_string($params['stx']);
if(!empty($sfl) && !empty($stx)){
if ($params['stx_cond'] === 'like') {
$conditions[] = "{$sfl} LIKE '%{$stx}%'";
} else {
$conditions[] = "{$sfl} = '{$stx}'";
}
}
}
// 권한 조건
if (!empty($params['use_level']) && $params['use_level'] === '1') {
$level_start = max(1, (int)$params['level_start']);
$level_end = min(10, (int)$params['level_end']);
$conditions[] = "(mb_level BETWEEN {$level_start} AND {$level_end})";
}
// 가입기간 조건
if (!empty($params['use_date']) && $params['use_date'] === '1') {
$date_start = isset($params['date_start']) ? sql_escape_string(trim($params['date_start'])) : '';
$date_end = isset($params['date_end']) ? sql_escape_string(trim($params['date_end'])) : '';
if ($date_start && $date_end) {
$conditions[] = "mb_datetime BETWEEN '{$date_start} 00:00:00' AND '{$date_end} 23:59:59'";
} elseif ($date_start) {
$conditions[] = "mb_datetime >= '{$date_start} 00:00:00'";
} elseif ($date_end) {
$conditions[] = "mb_datetime <= '{$date_end} 23:59:59'";
}
}
// 포인트 조건
if (!empty($params['use_point']) && $params['use_point'] === '1') {
$point = $params['point'];
$point_cond = $params['point_cond'];
if ($point != '') {
$point = (int)$point; // 정수로 캐스팅
switch ($point_cond) {
case 'lte':
$conditions[] = "mb_point <= {$point}";
break;
case 'eq':
$conditions[] = "mb_point = {$point}";
break;
default:
$conditions[] = "mb_point >= {$point}";
break;
}
}
}
// 휴대폰 번호 존재 조건
if (!empty($params['use_hp_exist']) && $params['use_hp_exist'] === '1') {
$conditions[] = "(mb_hp is not null and mb_hp != '')";
}
// 정보수신동의 조건
if (!empty($params['ad_range_only']) && $params['ad_range_only'] === '1') {
$range = $params['ad_range_type'] ?? '';
// 공통: 마케팅 목적 수집·이용 동의 + (필요 시) 제3자 동의
$needs_thirdparty = ($config['cf_sms_use'] !== '' || $config['cf_kakaotalk_use'] !== '');
$thirdparty_clause = $needs_thirdparty ? " AND mb_thirdparty_agree = 1" : "";
$base_marketing = "mb_marketing_agree = 1{$thirdparty_clause}";
if ($range === 'all') {
// 마케팅 동의 + (이메일 OR SMS 동의)
$conditions[] = "({$base_marketing} AND (mb_mailling = 1 OR mb_sms = 1))";
} elseif ($range === 'mailling_only') {
// 마케팅 동의 + 이메일 동의
$conditions[] = "({$base_marketing} AND mb_mailling = 1)";
} elseif ($range === 'sms_only') {
// 마케팅 동의 + SMS/카카오톡 동의
$conditions[] = "({$base_marketing} AND mb_sms = 1)";
} elseif ($range === 'month_confirm' || $range === 'custom_period') {
// 채널 필터 체크
$useEmail = !empty($params['ad_mailling']);
$useSms = !empty($params['ad_sms']);
if ($range === 'month_confirm') {
// 23개월 전 그 달
$start = date('Y-m-01 00:00:00', strtotime('-23 months'));
$end = date('Y-m-t 23:59:59', strtotime('-23 months'));
$emailDateCond = "mb_mailling_date BETWEEN '{$start}' AND '{$end}'";
$smsDateCond = "mb_sms_date BETWEEN '{$start}' AND '{$end}'";
} else {
// 수신동의기간 직접 입력 - custom_period
$date_start = $params['agree_date_start'] ?? '';
$date_end = $params['agree_date_end'] ?? '';
if ($date_start && $date_end) {
$emailDateCond = "mb_mailling_date BETWEEN '{$date_start} 00:00:00' AND '{$date_end} 23:59:59'";
$smsDateCond = "mb_sms_date BETWEEN '{$date_start} 00:00:00' AND '{$date_end} 23:59:59'";
} elseif ($date_start) {
$emailDateCond = "mb_mailling_date >= '{$date_start} 00:00:00'";
$smsDateCond = "mb_sms_date >= '{$date_start} 00:00:00'";
} elseif ($date_end) {
$emailDateCond = "mb_mailling_date <= '{$date_end} 23:59:59'";
$smsDateCond = "mb_sms_date <= '{$date_end} 23:59:59'";
} else {
$emailDateCond = "mb_mailling_date <> '0000-00-00 00:00:00'";
$smsDateCond = "mb_sms_date <> '0000-00-00 00:00:00'";
}
}
if (!$useEmail && !$useSms) {
$conditions[] = "0=1"; // 둘 다 해제 ⇒ 결과 0건
} else {
// 조건 조립
$parts = [];
if ($useEmail) $parts[] = "(mb_mailling = 1 AND {$emailDateCond})";
if ($useSms) $parts[] = "(mb_sms = 1 AND {$smsDateCond})";
$conditions[] = !empty($parts) ? '(' . implode(' OR ', $parts) . ')' : '';
}
}
}
// 차단 회원 조건
if (!empty($params['use_intercept']) && $params['use_intercept'] === '1') {
switch ($params['intercept']) {
case 'exclude':
$conditions[] = "mb_intercept_date = ''";
break;
case 'only':
$conditions[] = "mb_intercept_date != ''";
break;
}
}
return empty($conditions) ? '' : 'WHERE ' . implode(' AND ', $conditions);
}

578
adm/member_list_exel.php Normal file
View File

@ -0,0 +1,578 @@
<?php
$sub_menu = "200400";
require_once './_common.php';
require_once './member_list_exel.lib.php'; // 회원관리파일 공통 라이브러리
auth_check_menu($auth, $sub_menu, 'r');
// 파라미터 수집 및 유효성 검사
$params = get_member_export_params();
// 총건수
$total_count = 0;
$total_error = "";
try {
$total_count = member_export_get_total_count($params);
} catch (Exception $e) {
$total_error = $e->getMessage(); // 메서드 호출 괄호 필수
}
$g5['title'] = '회원관리파일';
require_once './admin.head.php';
$colspan = 14;
?>
<h2>회원 엑셀 생성</h2>
<div class="local_desc01 local_desc">
<p><b>회원수 <?php echo number_format(MEMBER_EXPORT_PAGE_SIZE);?>건 초과 시</b> <?php echo number_format(MEMBER_EXPORT_PAGE_SIZE);?>건 단위로 분리 저장되며, <b>엑셀 생성 최대 건수는 <?php echo number_format(MEMBER_EXPORT_MAX_SIZE);?>건</b>입니다. 초과 시 조건 추가 설정 후 재시도하시기 바랍니다.</p>
<p><b>수신동의 확인 대상은 만료일까지 1달 미만인 회원</b>을 기준으로 필터링됩니다.</p>
<br>
<p>파일 생성 시 서버에 임시 생성된 파일 중 <b>오늘 날짜를 제외 한 파일은 자동 삭제</b>되며, 수동 삭제 필요 시 <a href="<?php echo G5_ADMIN_URL;?>/member_list_file_delete.php"><b>회원관리파일 일괄삭제</b></a>에서 진행하시기 바랍니다.</p>
<p>회원 정보 수정은 <a href="<?php echo G5_ADMIN_URL;?>/member_list.php" class="link"><b>회원 관리</b></a>에서 진행하실 수 있습니다.</p>
<br>
<p><strong>친구톡 양식</strong>은 <b>카카오톡 사용 시</b>에만 이용 가능합니다.</p>
<?php if($config['cf_kakaotalk_use'] == "popbill") { ?>
<p><b>친구톡 (광고성 카카오톡 포함)</b>의 경우 기존 회원 데이터 엑셀 파일 다운로드 후 상단 <b>[친구톡 보내기]</b> 버튼을 누르면 <b>팝빌 홈페이지</b>로 이동하여 업로드 진행하실 수 있습니다.</p>
<?php } ?>
</div>
<?php if($config['cf_kakaotalk_use'] == "popbill") { ?>
<div class="btn_fixed_top">
<a href="https://popbill.com/App/Kakaotalk/FTS" target="_blank" class="btn btn_submit btn kakao_setting_btn" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="kakao-send-svg">
<path d="M2 21l21-9L2 3v7l15 2-15 2z"></path>
</svg>
친구톡 전송하기
</a>
</div>
<?php } ?>
<div class="local_ov01 local_ov">
<span class="btn_ov01">
<span class="ov_txt">총건수 </span>
<?php if($total_error != "") { ?>
<span class="ov_num"> <?php echo $total_error ?></span>
<?php } else {?>
<span class="ov_num"> <?php echo number_format($total_count) ?>건</span>
<?php } ?>
</span>
</div>
<!-- 회원 검색 필터링 폼 -->
<form id="fsearch" name="fsearch" class="member_list_data" method="get">
<input type="hidden" name="token" value="<?php echo get_token(); ?>">
<fieldset>
<legend class="sound_only">회원 검색 필터링</legend>
<div class="sch_table">
<!-- 검색어 적용 -->
<div class="sch_row">
<div class="label">
<label>
<input type="checkbox" name="use_stx" value="1" <?php echo isset($_GET['use_stx']) ? 'checked' : ''; ?>>
검색어 적용
</label>
</div>
<div class="field">
<select name="sfl">
<?php
// 검색어 옵션 : [정의] get_export_config() - adm/member_list_exel.lib.php;
foreach (get_export_config('sfl_list') as $val => $label) {
$selected = (isset($_GET['sfl']) && $_GET['sfl'] === $val) ? 'selected' : '';
echo "<option value=\"$val\" $selected>$label</option>";
}
?>
</select>
<input type="text" name="stx" value="<?php echo htmlspecialchars($_GET['stx'] ?? ''); ?>" placeholder="검색어 입력">
<span class="radio_group">
<label><input type="radio" name="stx_cond" value="like" <?php echo ($_GET['stx_cond'] ?? 'like') === 'like' ? 'checked' : ''; ?>> 포함</label>
<label><input type="radio" name="stx_cond" value="equal" <?php echo ($_GET['stx_cond'] ?? '') === 'equal' ? 'checked' : ''; ?>> 일치</label>
</span>
</div>
</div>
<!-- 레벨 적용 -->
<div class="sch_row">
<div class="label">
<label><input type="checkbox" name="use_level" value="1" <?php echo isset($_GET['use_level']) ? 'checked' : ''; ?>> 레벨 적용</label>
</div>
<div class="field">
<select name="level_start">
<?php for ($i = 1; $i <= 10; $i++): ?>
<option value="<?php echo $i; ?>" <?php echo (isset($_GET['level_start']) && $_GET['level_start'] == $i) ? 'selected' : ''; ?>><?php echo $i; ?></option>
<?php endfor; ?>
</select> ~
<select name="level_end">
<?php for ($i = 1; $i <= 10; $i++): ?>
<option value="<?php echo $i; ?>" <?php echo (isset($_GET['level_end']) && $_GET['level_end'] == $i) ? 'selected' : ''; ?>><?php echo $i; ?></option>
<?php endfor; ?>
</select>
</div>
</div>
<!-- 가입기간 적용 -->
<div class="sch_row">
<div class="label">
<label><input type="checkbox" name="use_date" value="1" <?php echo isset($_GET['use_date']) ? 'checked' : ''; ?>> 가입기간 적용</label>
</div>
<div class="field">
<input type="date" name="date_start" max="9999-12-31" value="<?php echo htmlspecialchars($_GET['date_start'] ?? ''); ?>"> ~
<input type="date" name="date_end" max="9999-12-31" value="<?php echo htmlspecialchars($_GET['date_end'] ?? ''); ?>">
</div>
</div>
<!-- 포인트 적용 -->
<div class="sch_row">
<div class="label">
<label><input type="checkbox" name="use_point" value="1" <?php echo isset($_GET['use_point']) ? 'checked' : ''; ?>> 포인트 적용</label>
</div>
<div class="field">
<input type="number" name="point" value="<?php echo htmlspecialchars($_GET['point'] ?? ''); ?>" placeholder="포인트 입력">
<span class="radio_group">
<label><input type="radio" name="point_cond" value="gte" <?php echo ($_GET['point_cond'] ?? 'gte') === 'gte' ? 'checked' : ''; ?>> 이상</label>
<label><input type="radio" name="point_cond" value="lte" <?php echo ($_GET['point_cond'] ?? '') === 'lte' ? 'checked' : ''; ?>> 이하</label>
<label><input type="radio" name="point_cond" value="eq" <?php echo ($_GET['point_cond'] ?? '') === 'eq' ? 'checked' : ''; ?>> 일치</label>
</span>
</div>
</div>
<!-- 차단회원 조건 -->
<div class="sch_row">
<div class="label">
<label><input type="checkbox" name="use_intercept" value="1" <?php echo isset($_GET['use_intercept']) ? 'checked' : ''; ?>> 차단회원</label>
</div>
<div class="field">
<select name="intercept" id="intercept">
<?php
// 차단회원 옵션 : [정의] get_export_config() - adm/member_list_exel.lib.php
foreach (get_export_config('intercept_list') as $val => $label) {
$selected = (($_GET['intercept'] ?? '') === $val) ? 'selected' : '';
echo "<option value=\"$val\" $selected>$label</option>";
}
?>
</select>
</div>
</div>
<!-- 휴대폰 번호 조건 - 초기세팅(설정에 휴대폰번호가 보이기/필수입력이면 기본값 checked로 설정) -->
<div class="sch_row">
<div class="label">
<label>
<?php $use_hp_checked = isset($_GET['token']) ? (isset($_GET['use_hp_exist']) ? 'checked' : '') : (($config['cf_use_hp'] || $config['cf_req_hp']) ? 'checked' : '');?>
<input type="checkbox" name="use_hp_exist" value="1" <?php echo $use_hp_checked; ?>> 휴대폰 번호 있는 경우만
</label>
</div>
</div>
<!-- 정보수신동의 조건 -->
<div class="sch_row">
<div class="label">
<label><input type="checkbox" name="ad_range_only" value="1" <?php echo isset($_GET['ad_range_only']) ? 'checked' : ''; ?>> 정보수신동의에 동의한 경우만</label>
</div>
<!-- 안내 문구 -->
<div class="field">
<p class="sch_notice">「정보통신망이용촉진및정보보호등에관한법률」에 따라 <b>광고성 정보 수신동의 여부</b>를 <b>매2년</b>마다 확인해야 합니다.</p>
</div>
</div>
<div class="sch_row <?php echo isset($_GET['ad_range_only']) ? '' : 'is-hidden'; ?>">
<div class="ad_range_wrap">
<div class="ad_range_box">
<div class="label">
<label for="ad_range_type">회원범위</label>
</div>
<div class="field">
<select name="ad_range_type" id="ad_range_type">
<?php
foreach (get_export_config('ad_range_list') as $val => $label) {
$selected = (($_GET['ad_range_type'] ?? '') === $val) ? 'selected' : '';
echo "<option value=\"$val\" $selected>$label</option>";
}
?>
</select>
<div class="ad_range_wrap">
<!-- 기간 직접 입력 -->
<div class="ad_range_box <?php echo isset($_GET['ad_range_only']) && ($_GET['ad_range_type'] ?? '') == 'custom_period' ? '' : 'is-hidden'; ?>">
<div class="field">
<input type="date" name="agree_date_start" max="9999-12-31" value="<?php echo htmlspecialchars($_GET['agree_date_start'] ?? date('Y-m-d', strtotime('-1 month'))); ?>"> ~
<input type="date" name="agree_date_end" max="9999-12-31" value="<?php echo htmlspecialchars($_GET['agree_date_end'] ?? date('Y-m-d')); ?>">
<p>* 광고성 정보 수신(<b>이메일 또는 SMS/카카오톡</b>) 동의일자 기준</p>
</div>
</div>
<!-- 설명 문구 -->
<?php
$thirdpartyLbl = (!empty($config['cf_sms_use']) || !empty($config['cf_kakaotalk_use'])) ? ' / <b>개인정보 제3자 제공</b>' : '';
$ad_range_text = [
'all' => "* <b>광고성 정보 수신(이메일 또는 SMS/카카오톡)</b> / <b>마케팅 목적의 개인정보 수집 및 이용</b>{$thirdpartyLbl}에 모두 동의한 회원을 선택합니다.",
'mailling_only' => "* <b>광고성 이메일 수신</b> / <b>마케팅 목적의 개인정보 수집 및 이용</b>{$thirdpartyLbl}에 모두 동의한 회원을 선택합니다.",
'sms_only' => "* <b>광고성 SMS/카카오톡 수신</b> / <b>마케팅 목적의 개인정보 수집 및 이용</b>{$thirdpartyLbl}에 모두 동의한 회원을 선택합니다.",
'month_confirm' => "* 23개월 전(" . date('Y년 m월', strtotime('-23 month')) . ") <b>광고성 정보 수신 동의(이메일 또는 SMS/카카오톡)</b>한 회원을 선택합니다."
];
if (isset($_GET['ad_range_only'], $_GET['ad_range_type']) && isset($ad_range_text[$_GET['ad_range_type']])) {
echo '<div class="ad_range_box"><p>' . $ad_range_text[$_GET['ad_range_type']] . '</p></div>';
}
?>
</div>
<br>
</div>
</div>
</div>
</div>
<!-- 채널 체크박스 -->
<div class="sch_row <?php echo isset($_GET['ad_range_only']) && in_array($_GET['ad_range_type'], ['month_confirm', 'custom_period']) ? '' : 'is-hidden'; ?>">
<div class="ad_range_wrap">
<div class="ad_range_box">
<div class="label">
</div>
<div class="field">
<?php $ad_mailling_checked = isset($_GET['token']) ? (isset($_GET['ad_mailling']) ? 'checked' : '') : 'checked';?>
<?php $ad_sms_checked = isset($_GET['token']) ? (isset($_GET['ad_sms']) ? 'checked' : '') : 'checked';?>
<label><input type="checkbox" name="ad_mailling" value="1" <?php echo $ad_mailling_checked; ?>> 광고성 이메일 수신</label>
<label><input type="checkbox" name="ad_sms" value="1" <?php echo $ad_sms_checked; ?>> 광고성 SMS/카카오톡 수신</label>
</div>
</div>
</div>
</div>
<div class="sch_btn">
<button type="button" id="btnExcelDownload">엑셀파일 다운로드</button>
<?php if($config['cf_kakaotalk_use'] == "popbill") { ?>
<button type="button" id="btnExcelDownloadPopbill">엑셀파일 다운로드 (친구톡 양식)</button>
<?php } ?>
<button type="button" class="btn_reset" onclick="location.href='?'">초기화</button>
</div>
</div>
</fieldset>
</form>
<script>
document.querySelector('input[name="ad_range_only"]').addEventListener('change', function () {
document.querySelectorAll('.ad_range_wrap').forEach(el => {
el.classList.toggle('is-hidden', !this.checked);
});
});
document.querySelectorAll('#fsearch input, #fsearch select').forEach(el => {
const submit = () => document.getElementById('fsearch').submit();
el.addEventListener(el.type === 'date' ? 'blur' : 'change', submit);
el.addEventListener('keydown', e => {
if (e.key === 'Enter') {
e.preventDefault();
submit();
}
});
});
</script>
<script>
let eventSource = null;
// 일반 엑셀 다운로드 버튼 클릭
document.getElementById('btnExcelDownload').addEventListener('click', () => {
startExcelDownload(1);
});
// 팝빌 양식 다운로드 버튼 클릭
<?php if($config['cf_kakaotalk_use'] == "popbill") { ?>
document.getElementById('btnExcelDownloadPopbill').addEventListener('click', () => {
showDownloadPopupPopill();
});
<?php } ?>
// 엑셀 다운로드 실행
// 1. 기존 SSE 종료
function closePreviousEventSource() {
if (eventSource) {
eventSource.close();
eventSource = null;
}
}
// 2. FormData QueryString 변환
function buildDownloadParams(formatType, selectedFields = []) {
const formData = new FormData(document.getElementById('fsearch'));
const params = new URLSearchParams(formData);
params.append('mode', 'start');
params.append('formatType', formatType);
if (formatType === 2 && selectedFields.length > 0) {
params.append('fields', selectedFields.join(','));
}
return params.toString();
}
// 3. 메인 함수
function startExcelDownload(formatType, selectedFields = []) {
closePreviousEventSource();
const query = buildDownloadParams(formatType, selectedFields);
showDownloadPopup();
eventSource = new EventSource(`member_list_exel_export.php?${query}`);
eventSource.onmessage = handleProgressUpdate();
eventSource.onerror = handleDownloadError();
}
// 다운로드 팝업 표시
function showDownloadPopup() {
const bodyHTML = `
<div class="excel-download-progress">
<div class="progress-desc">
<p class="progress-summary">총 <strong>0</strong>개 파일로 분할됩니다</p>
<p class="progress-message"><strong>(0 / 0)</strong> 파일 다운로드 중</p>
<p class="progress-error"></p>
</div>
<div class="progress-spinner">
<div class="spinner"></div>
<p class="loading-message">
엑셀 파일을 생성 중입니다. 잠시만 기다려주세요.<br>
현재 데이터 기준으로 <strong id="estimatedTimeText"></strong> 정도 소요될 수 있습니다.<br>
<strong>페이지를 벗어나거나 닫으면 다운로드가 중단</strong>되니, 작업 완료까지 기다려 주세요.
</p>
</div>
<div class="progress-box">
<div class="progress-download-box"></div>
</div>
</div>
`;
PopupManager.render('엑셀 다운로드 진행 중', bodyHTML, '', { disableOutsideClose: true });
// 닫기 버튼 이벤트 핸들링
const closeBtn = document.querySelector('.popup-close-btn');
if (closeBtn) {
closeBtn.removeAttribute('onclick');
closeBtn.addEventListener('click', handlePopupCloseWithConfirm);
}
}
// 닫기 버튼 클릭 시 다운로드 중단 여부 확인
function handlePopupCloseWithConfirm(e) {
if (eventSource) {
const confirmClose = confirm("엑셀 다운로드가 진행 중입니다.\n정말 중지하시겠습니까?");
if (!confirmClose) {
e.preventDefault();
return;
}
eventSource.close();
eventSource = null;
alert("엑셀 다운로드가 중단되었습니다.");
}
PopupManager.close('popupOverlay');
}
// 친구톡 양식(팝빌) - 항목 선택 팝업
function showDownloadPopupPopill() {
const baseFields = [
['mb_id', '아이디'], ['mb_nick', '닉네임'], ['mb_point', '포인트'], ['mb_level', '권한'],
['mb_email', '이메일'], ['mb_homepage', '홈페이지'], ['mb_datetime', '회원가입일'], ['mb_intercept_date', '차단여부'],
['mb_mailling', '광고성 이메일 수신동의'], ['mb_mailling_date', '광고성 이메일 수신동의일자'],
['mb_sms', '광고성 SMS/카카오톡 수신동의'], ['mb_sms_date', '광고성 SMS/카카오톡 수신동의일자'],
['mb_marketing_agree', '마케팅목적의개인정보수집및이용동의여부'], ['mb_marketing_date', '마케팅목적의개인정보수집및이용동의일자'],
['mb_thirdparty_agree', '개인정보제3자제공동의여부'], ['mb_thirdparty_date', '개인정보제3자제공동의일자']
];
const extraFields = Array.from({ length: 10 }, (_, i) => [`mb_${i + 1}`, `여분 필드 ${i + 1}`]);
let baseFieldHTML = '';
baseFields.forEach(([value, label]) => {
baseFieldHTML += `<label><input type="checkbox" name="fields" value="${value}"> ${label}</label>\n`;
});
let extraFieldHTML = '';
extraFields.forEach(([value, label]) => {
extraFieldHTML += `<label><input type="checkbox" name="fields" value="${value}"> ${label}</label>\n`;
});
const bodyHTML = `
<div class="excel-download-progress">
<p>팝빌 친구톡 전송을 위한 엑셀 양식을 다운로드하실 수 있습니다.</p>
<p><b>전화번호</b>와 <b>이름</b>은 필수 입력 항목이며, 추가로 변수1부터 변수3까지 최대 3개의 선택 항목을 입력하실 수 있습니다.</p>
<div id="selectedFieldsPreview" class="selected-fields-preview"><strong>선택된 항목:</strong></div>
<div id="fieldSelectForm" class="field-select-form">
${baseFieldHTML}
<div class="field-separator"></div>
${extraFieldHTML}
</div>
</div>
`;
const footerHTML = `<button type="button" onclick="submitSelectedFields()">선택 완료</button>`;
PopupManager.render('엑셀 양식에 포함할 항목 선택', bodyHTML, footerHTML, { disableOutsideClose: true });
bindFieldSelectEvents();
}
// 체크박스 선택 시 최대 3개 제한 및 선택된 항목 미리보기 표시
function bindFieldSelectEvents() {
const fieldSelectForm = document.getElementById('fieldSelectForm');
if (!fieldSelectForm) return;
fieldSelectForm.addEventListener('change', function (e) {
if (e.target.name === 'fields') {
const selected = fieldSelectForm.querySelectorAll('input[name="fields"]:checked');
if (selected.length > 3) {
alert("최대 3개까지 선택 가능합니다.");
e.target.checked = false;
return;
}
// 선택된 항목 표시
const previewContainer = document.getElementById('selectedFieldsPreview');
let spans = '<strong>선택된 항목:</strong>';
selected.forEach(field => {
const label = field.parentElement.textContent.trim();
spans += `<span class="field-tag">${label}</span>`;
});
previewContainer.innerHTML = spans;
}
});
}
// 친구톡 양식 - 항목 선택 후 선택완료 버튼 클릭
function submitSelectedFields() {
const checkboxes = document.querySelectorAll('#fieldSelectForm input[name="fields"]:checked');
const selected = Array.from(checkboxes).map(cb => cb.value);
if (selected.length > 3) {
alert("최대 3개까지만 선택할 수 있습니다.");
return;
}
// 항목을 하나도 선택하지 않았을 때 안내 알럿
if (selected.length === 0) {
const confirmProceed = confirm("선택한 항목이 없습니다. 항목 없이 엑셀을 다운로드하시겠습니까?");
if (!confirmProceed) return;
}
PopupManager.close('popupOverlay');
startExcelDownload(2, selected); // formatType 2: Popbill 다운로드
}
// 엑셀 생성 및 다운로드 실행
function handleProgressUpdate() {
return function(e) {
const data = JSON.parse(e.data);
const { status, downloadType, message, total, current, totalChunks, currentChunk, zipFile, files, filePath } = data;
// DOM 요소 캐싱
const titleEl = document.getElementById('popupTitle');
const summaryEl = document.querySelector('.progress-summary');
const messageEl = document.querySelector('.progress-message');
const spinnerEl = document.querySelector('.progress-spinner');
const resultEl = document.querySelector('.loading-message');
const downloadBoxEl = document.querySelector('.progress-download-box');
const errorEl = document.querySelector('.progress-error');
if (status === "progress")
{
summaryEl.innerHTML = `총 <strong>${totalChunks}</strong>개 파일로 ` + (downloadType === 2 ? `분할 생성됩니다` : `다운로드됩니다`) + ` (총 ${total.toLocaleString('ko-KR')}건)`;
messageEl.innerHTML = downloadType === 2 ? `<strong>(${currentChunk} / ${totalChunks})</strong> 파일 생성 중` : `엑셀 파일 생성 중`;
/* 작업 소요 시간 : 예상 시간 (1만건당 10초) */
const sec = Math.max(5, Math.ceil(total * 0.0012 * 1.2)); // 최소 5초 보장
const text = `예상 처리 시간은 약 ${sec >= 60 ? `${Math.floor(sec / 60)}분 ${sec % 60}초` : `${sec}초`}`;
document.getElementById('estimatedTimeText').innerText = text;
}
else if (status === "zipping")
{
summaryEl.innerHTML = `총 <strong>${totalChunks}</strong>개 파일이 압축파일로 생성됩니다`;
messageEl.innerHTML = `<strong>${totalChunks}</strong> 파일 압축하는 중`;
}
else if (status === "zippingError")
{
errorEl.innerHTML = message;
}
else if (status === "error")
{
summaryEl.innerHTML = `엑셀 파일 다운로드 실패`;
resultEl.innerHTML = '';
spinnerEl?.classList.add('is-hidden');
const parts = message.split(/<br\s*\/?>/i);
messageEl.innerHTML = parts[0] || '';
errorEl.innerHTML = parts.slice(1).join('<br>') || '';
// SSE 작업 닫기
eventSource?.close();
eventSource = null;
}
else if (status === "done")
{
// SSE 작업 닫기
eventSource?.close();
eventSource = null;
titleEl.textContent = '엑셀 파일 다운로드 완료';
messageEl.innerHTML = `<strong>총 ${total.toLocaleString('ko-KR')}건의 데이터 다운로드가 완료되었습니다!</strong>`;
spinnerEl?.classList.add('is-hidden');
let html = '<p>* 자동으로 다운로드가 되지 않았다면 아래 버튼을 클릭해주세요.</p>';
const baseUrl = `<?php echo G5_DATA_URL; ?>/member_list/<?php echo date('Ymdhis'); ?>/`; // 공통 URL 분리
if (zipFile) {
const url = `${filePath}/${zipFile}`;
html += `<a href="${url}" class="btn btn_03" download>압축파일 다운로드</a>`;
downloadBoxEl.innerHTML = html;
triggerAutoDownload(url, zipFile);
} else if (files?.length) {
files.forEach((file, index) => {
const url = `${filePath}/${file}`;
html += `<a class="btn btn_03" href="${url}" download>엑셀파일 다운로드 ${index + 1}</a>`;
});
downloadBoxEl.innerHTML = html;
if (files.length === 1) {
const url = `${filePath}/${files[0]}`;
triggerAutoDownload(url, files[0]);
} else {
summaryEl.innerHTML = `총 <strong>${totalChunks}</strong>개 파일이 생성되었습니다. 아래 버튼을 눌러 다운로드 받아주세요.`;
}
}
}
}
}
// SSE 오류 처리
function handleDownloadError() {
return function(e){
const errorMessage = e?.message || e?.data || '알 수 없는 오류가 발생했습니다.';
document.querySelector('.progress-summary').innerHTML = `엑셀 파일 다운로드 실패`;
document.querySelector('.progress-message').innerHTML = `엑셀 파일 다운로드에 실패하였습니다`;
document.querySelector('.progress-error').innerHTML = errorMessage;
document.querySelector('.loading-message').innerHTML = '';
document.querySelector('.progress-spinner').classList.add('is-hidden');
if (eventSource) {
eventSource.close();
eventSource = null;
}
}
}
// 자동 다운로드 실행
function triggerAutoDownload(url, filename) {
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
</script>
<?php
require_once './admin.tail.php';

View File

@ -0,0 +1,559 @@
<?php
require_once './_common.php';
require_once './member_list_exel.lib.php'; // 회원관리파일 공통 라이브러리 (상수, 검색 옵션 설정, SQL WHERE 등)
include_once(G5_LIB_PATH.'/PHPExcel.php');
ini_set('memory_limit', '-1');
session_write_close(); // 세션 종료 및 잠금 해제 (백그라운드 작업을 위해 필요)
// 파라미터 수집 및 유효성 검사
$params = get_member_export_params();
if (!$params || !is_array($params)) {
member_export_send_progress("error", "데이터가 올바르게 전달되지 않아 작업에 실패하였습니다.");
member_export_write_log([], ['success' => false, 'error' => '데이터가 올바르게 전달되지 않아 작업에 실패하였습니다.']);
exit;
}
// 기존 생성된 엑셀 파일 삭제 - LOG 및 오늘 날짜 폴더 제외
$resultExcelDelete = member_export_delete();
// 서버 전송 이벤트(SSE)를 위한 헤더 설정
member_export_set_sse_headers();
// 모드 확인
$mode = $_GET['mode'] ?? '';
if ($mode !== 'start') {
member_export_send_progress("error", "잘못된 요청 입니다.");
member_export_write_log($params, ['success' => false, 'error' => '잘못된 요청 입니다.']);
exit;
}
/**
* 회원 내보내기 처리 실행 (예외 처리 포함)
*/
try {
main_member_export($params);
}
catch (Exception $e)
{
// 에러 로그 저장 및 SSE 에러 전송
error_log("[Member Export Error] " . $e->getMessage());
member_export_send_progress("error", $e->getMessage());
member_export_write_log($params, ['success' => false, 'error' => $e->getMessage()]);
}
/**
* 메인 내보내기 프로세스
*/
function main_member_export($params)
{
$total = member_export_get_total_count($params);
if($total > MEMBER_EXPORT_MAX_SIZE){
throw new Exception("엑셀 다운로드 가능 범위(최대 " . number_format(MEMBER_EXPORT_MAX_SIZE) . "건)를 초과했습니다.<br>조건을 추가로 설정하신 후 다시 시도해 주세요.");
}
if($total <= 0){
throw new Exception("조회된 데이터가 없어 엑셀 파일을 생성할 수 없습니다.<br>조건을 추가로 설정하신 후 다시 시도해 주세요.");
}
$fileName = 'member_'.MEMBER_BASE_DATE;
$fileList = [];
$zipFileName = '';
if ($total > MEMBER_EXPORT_PAGE_SIZE) {
// 대용량 데이터 - 분할 처리
$pages = (int)ceil($total / MEMBER_EXPORT_PAGE_SIZE);
member_export_send_progress("progress", "", 2, $total, 0, $pages, 0);
for ($i = 1; $i <= $pages; $i++) {
$params['page'] = $i;
member_export_send_progress("progress", "", 2, $total, ($pages == $i ? $total : $i * MEMBER_EXPORT_PAGE_SIZE), $pages, $i);
try {
$data = member_export_get_data($params);
$fileList[] = member_export_create_excel($data, $fileName, $i, $params['formatType']);
} catch (Exception $e) {
throw new Exception("{$pages}개 중 {$i}번째 파일을 생성하지 못했습니다<br>" . $e->getMessage());
}
}
// 압축 파일 생성
if (count($fileList) > 1) {
member_export_send_progress("zipping", "", 2, $total, $total, $pages, $i);
$zipResult = member_export_create_zip($fileList, $fileName); // 압축 파일 생성
if($zipResult['error']){
member_export_write_log($params, ['success' => false, 'error' => $zipResult['error']]);
member_export_send_progress("zippingError", $zipResult['error']);
}
if ($zipResult && $zipResult['result']) {
member_export_delete($fileList); // 압축 후 엑셀 파일 제거
$zipFileName = $zipResult['zipFile'];
}
}
} else {
// 소용량 데이터 - 단일 파일
member_export_send_progress("progress", "", 1, $total, 0);
$data = member_export_get_data($params);
member_export_send_progress("progress", "", 1, $total, $total/2);
$fileList[] = member_export_create_excel($data, $fileName, 0, $params['formatType']);
member_export_send_progress("progress", "", 1, $total, $total);
}
member_export_write_log($params, ['success' => true, 'total' => $total, 'files' => $fileList, 'zip' => $zipFileName ?? null]);
member_export_send_progress("done", "", 2, $total, $total, $pages, $pages, $fileList, $zipFileName);
}
/**
* 진행률 전송
*/
function member_export_send_progress($status, $message = "", $downloadType = 1, $total = 1, $current = 1, $totalChunks = 1, $currentChunk = 1, $files = [], $zipFile = '')
{
// 연결 상태 확인
if (connection_aborted()) return;
$data = [
'status' => $status,
'message' => $message,
'downloadType' => $downloadType,
'total' => $total,
'current' => $current,
'totalChunks' => $totalChunks,
'currentChunk' => $currentChunk,
'files' => $files,
'zipFile' => $zipFile,
'filePath' => G5_DATA_URL . "/" . MEMBER_BASE_DIR . "/" . MEMBER_BASE_DATE,
];
echo "data: " . json_encode($data, JSON_UNESCAPED_UNICODE) . "\n\n";
// 더 안정적인 플러시
if (ob_get_level()) ob_end_flush();
flush();
}
/**
* 엑셀 내보내기 설정
*/
function member_export_get_config($type)
{
$configs = [
1 => [
'title' => ["회원관리파일(일반)"],
'headers' => ['아이디', '이름', '닉네임', '휴대폰번호', '전화번호', '이메일', '주소', '회원권한', '포인트', '가입일', '차단',
'광고성 이메일 수신동의', '광고성 이메일 동의일자', '광고성 SMS/카카오톡 수신동의', '광고성 SMS/카카오톡 동의일자',
'마케팅목적의개인정보수집및이용동의', '마케팅목적의개인정보수집및이용동의일자', '개인정보제3자제공동의', '개인정보제3자제공동의일자'],
'fields' => ['mb_id', 'mb_name', 'mb_nick', 'mb_hp', 'mb_tel', 'mb_email', 'mb_addr1', 'mb_level', 'mb_point', 'mb_datetime', 'mb_intercept_date',
'mb_mailling','mb_mailling_date', 'mb_sms','mb_sms_date', 'mb_marketing_agree',
'mb_marketing_date', 'mb_thirdparty_agree', 'mb_thirdparty_date'],
'widths' => [20, 20, 20, 20, 20, 30, 30, 10, 15, 25, 10, 20, 25, 20, 25, 20, 25, 20, 25],
],
2 => [
'title' => ["회원관리파일(팝빌)"],
'headers' => ['휴대폰번호', '이름', '변수1', '변수2', '변수3'],
'fields' => ['mb_hp', 'mb_name'],
'widths' => [20, 15, 30, 30, 30],
],
];
return isset($configs[$type]) ? $configs[$type] : $configs[1];
}
/**
* SSE 헤더 설정
*/
function member_export_set_sse_headers()
{
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no');
if (ob_get_level()) ob_end_flush();
ob_implicit_flush(true);
}
/**
* 엑셀 컬럼 문자 반환
*/
function member_export_column_char($i)
{
return chr(65 + $i);
}
/**
* 회원 데이터 조회
*/
function member_export_get_data($params)
{
global $g5;
$config = member_export_get_config($params['formatType']);
$fields = $config['fields'];
// 팝빌 타입인 경우 var 추가
if ($params['formatType'] == 2 && !empty($params['vars'])) {
$fields = array_merge($fields, array_values($params['vars']));
}
$fields = array_unique($fields);
// SQL 변환 맵 (가공이 필요한 필드만 정의)
$sqlTransformMap = [
'mb_datetime' => "IF(mb_datetime = '0000-00-00 00:00:00', '', mb_datetime) AS mb_datetime",
'mb_intercept_date' => "IF(mb_intercept_date != '', '차단됨', '정상') AS mb_intercept_date",
'mb_sms' => "IF(mb_sms = '1', '동의', '미동의') AS mb_sms",
'mb_sms_date' => "IF(mb_sms != '1' OR mb_sms_date = '0000-00-00 00:00:00', '', mb_sms_date) AS mb_sms_date",
'mb_mailling' => "IF(mb_mailling = '1', '동의', '미동의') AS mb_mailling",
'mb_mailling_date' => "IF(mb_mailling != '1' OR mb_mailling_date = '0000-00-00 00:00:00', '', mb_mailling_date) AS mb_mailling_date",
'mb_marketing_agree' => "IF(mb_marketing_agree = '1', '동의', '미동의') AS mb_marketing_agree",
'mb_marketing_date' => "IF(mb_marketing_agree != '1' OR mb_marketing_date = '0000-00-00 00:00:00', '', mb_marketing_date) AS mb_marketing_date",
'mb_thirdparty_agree' => "IF(mb_thirdparty_agree = '1', '동의', '미동의') AS mb_thirdparty_agree",
'mb_thirdparty_date' => "IF(mb_thirdparty_agree != '1' OR mb_thirdparty_date = '0000-00-00 00:00:00', '', mb_thirdparty_date) AS mb_thirdparty_date",
];
// SQL 필드 생성
$sqlFields = [];
foreach ($fields as $field) {
$sqlFields[] = $sqlTransformMap[$field] ?? $field;
}
$field_list = implode(', ', $sqlFields);
$where = member_export_build_where($params);
$page = (int)($params['page'] ?? 1);
if ($page < 1) $page = 1;
$offset = ($page - 1) * MEMBER_EXPORT_PAGE_SIZE;
$sql = "SELECT {$field_list} FROM {$g5['member_table']} {$where} ORDER BY mb_no DESC LIMIT {$offset}, " . MEMBER_EXPORT_PAGE_SIZE;
$result = sql_query($sql);
if (!$result) {
throw new Exception("데이터 조회에 실패하였습니다");
}
$excelData = [$config['title'], $config['headers']];
while ($row = sql_fetch_array($result)) {
$rowData = [];
foreach ($fields as $field) {
$rowData[] = $row[$field] ?? '';
}
$excelData[] = $rowData;
}
return $excelData;
}
/**
* 엑셀 파일 생성
*/
function member_export_create_excel($data, $fileName, $index = 0, $type = 1)
{
$config = member_export_get_config($type);
if (!class_exists('PHPExcel')) {
error_log('[Member Export Error] PHPExcel 라이브러리를 찾을 수 없습니다.');
throw new Exception('파일 생성 중 내부 오류가 발생했습니다: PHPExcel 라이브러리를 찾을 수 없습니다.');
}
// 현재 설정값 백업
$currentCache = PHPExcel_Settings::getCacheStorageMethod();
// 캐싱 모드 설정 (엑셀 생성 전용)
$cacheMethods = [
PHPExcel_CachedObjectStorageFactory::cache_to_discISAM,
PHPExcel_CachedObjectStorageFactory::cache_in_memory_serialized
];
foreach ($cacheMethods as $method) {
if (PHPExcel_Settings::setCacheStorageMethod($method)) {
break;
}
}
try {
$excel = new PHPExcel();
$sheet = $excel->setActiveSheetIndex(0);
// 헤더 스타일 적용
$last_char = member_export_column_char(count($config['headers']) - 1);
$sheet->getStyle("A2:{$last_char}2")->applyFromArray([
'fill' => [
'type' => PHPExcel_Style_Fill::FILL_SOLID,
'startcolor' => ['rgb' => 'D9E1F2'], // 연파랑 배경
],
]);
// 셀 정렬 및 줄바꿈 설정
$sheet->getStyle("A:{$last_char}")->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER)->setWrapText(true);
// 컬럼 너비 설정
foreach ($config['widths'] as $i => $width) {
$sheet->getColumnDimension(member_export_column_char($i))->setWidth($width);
}
// 데이터 입력
$sheet->fromArray($data, NULL, 'A1');
// 디렉토리 확인
member_export_ensure_directory(MEMBER_EXPORT_DIR);
// 파일명 생성
$subname = $index == 0 ? 'all' : sprintf("%02d", $index);
$filename = $fileName . "_" . $subname . ".xlsx";
$filePath = MEMBER_EXPORT_DIR . "/" . $filename;
// 파일 저장
$writer = PHPExcel_IOFactory::createWriter($excel, 'Excel2007');
$writer->setPreCalculateFormulas(false);
$writer->save($filePath);
unset($excel, $sheet, $writer); // 생성 완료 후 메모리 해제
}
catch (Exception $e)
{
throw new Exception("엑셀 파일 생성에 실패하였습니다: " . $e->getMessage());
}
finally
{
// 캐싱 모드 원래 상태로 복원
if ($currentCache) {
PHPExcel_Settings::setCacheStorageMethod($currentCache);
}
}
return $filename;
}
/**
* 압축 파일 생성
*/
function member_export_create_zip($files, $zipFileName)
{
if (!class_exists('ZipArchive')) {
error_log('[Member Export Error] ZipArchive 클래스를 사용할 수 없습니다.');
return ['error' => '파일을 압축하는 중 문제가 발생했습니다. 개별 파일로 제공됩니다.<br>: ZipArchive 클래스를 사용할 수 없습니다.'];
}
member_export_ensure_directory(MEMBER_EXPORT_DIR);
$destinationZipPath = rtrim(MEMBER_EXPORT_DIR, "/") . "/" . $zipFileName . ".zip";
$zip = new ZipArchive();
if ($zip->open($destinationZipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
return ['error' => "파일을 압축하는 중 문제가 발생했습니다. 개별 파일로 제공됩니다."];
}
foreach ($files as $file) {
$filePath = MEMBER_EXPORT_DIR . "/" . $file;
if (file_exists($filePath)) {
$zip->addFile($filePath, basename($filePath));
}
}
$result = $zip->close();
return [
'result' => $result,
'zipFile' => $zipFileName . ".zip",
'zipPath' => $destinationZipPath,
];
}
/**
* 디렉토리 생성 및 확인
*/
function member_export_ensure_directory($dir)
{
if (!is_dir($dir)) {
if (!@mkdir($dir, G5_DIR_PERMISSION, true)) {
throw new Exception("디렉토리 생성 실패");
}
@chmod($dir, G5_DIR_PERMISSION);
}
if (!is_writable($dir)) {
throw new Exception("디렉토리 쓰기 권한 없음");
}
}
/**
* 파일 삭제 - 값이 있으면 해당 파일만 삭제, 없으면 디렉토리 내 모든 파일 삭제
* - 알집 생성 완료 시 엑셀 파일 제거
* - 작업 전 오늘 날짜 폴더 및 log 폴더를 제외한 나머지 파일 모두 제거
*/
function member_export_delete($fileList = [])
{
$cnt = 0;
// 파일 리스트가 있는 경우 -> 해당 파일만 삭제
if (!empty($fileList)) {
foreach ($fileList as $file) {
$filePath = rtrim(MEMBER_EXPORT_DIR, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $file;
if (file_exists($filePath) && is_file($filePath) && @unlink($filePath)) {
$cnt++;
}
}
}
// 파일 리스트가 없는 경우 -> 디렉토리 내 모든 파일 삭제
else {
$files = glob(rtrim(G5_DATA_PATH . "/" . MEMBER_BASE_DIR, '/') . '/*');
function deleteFolder($dir) {
foreach (glob($dir . '/{.,}*', GLOB_BRACE) as $item) {
if (in_array(basename($item), ['.', '..'])) continue;
is_dir($item) ? deleteFolder($item) : unlink($item);
}
rmdir($dir);
}
foreach ($files as $file) {
$name = basename($file);
// log 폴더와 오늘 날짜로 시작하는 폴더는 제외
if ($name === 'log' || preg_match('/^' . date('Ymd') . '\d{6}$/', $name)) continue;
if (is_file($file) && pathinfo($file, PATHINFO_EXTENSION) !== 'log' && @unlink($file)) {
$cnt++;
} elseif (is_dir($file)) {
deleteFolder($file); // 재귀 폴더 삭제 함수 사용
$cnt++;
}
}
}
return $cnt;
}
/**
* 로그 작성
*/
function member_export_write_log($params, $result = [])
{
global $member;
$maxSize = 1024 * 1024 * 2; // 2MB
$maxFiles = 10; // 최대 로그 파일 수 (필요시 조정)
$username = $member['mb_id'] ?? 'guest';
$datetime = date("Y-m-d H:i:s");
if (!is_dir(MEMBER_LOG_DIR)) {
@mkdir(MEMBER_LOG_DIR, G5_DIR_PERMISSION, true);
@chmod(MEMBER_LOG_DIR, G5_DIR_PERMISSION);
}
$logFiles = glob(MEMBER_LOG_DIR . "/export_log_*.log") ?: [];
// 최신 파일 기준 정렬 (최신 → 오래된)
usort($logFiles, fn($a, $b) => filemtime($b) - filemtime($a));
$latestLogFile = $logFiles[0] ?? null;
// 용량 기준으로 새 파일 생성
if (!$latestLogFile || filesize($latestLogFile) >= $maxSize) {
$latestLogFile = MEMBER_LOG_DIR . "/export_log_" . date("YmdHi") . ".log";
file_put_contents($latestLogFile, '');
array_unshift($logFiles, $latestLogFile);
}
// 최대 파일 수 초과 시 오래된 파일 제거
if (count($logFiles) > $maxFiles) {
$filesToDelete = array_slice($logFiles, $maxFiles);
foreach ($filesToDelete as $file) {
@unlink($file);
}
}
$formatType = (isset($params['formatType']) && $params['formatType'] == 2) ? '팝빌' : '일반';
$success = isset($result['success']) && $result['success'] === true;
$status = $success ? '성공' : '실패';
// 조건 정리
$condition = [];
// 검색 조건
if ($params['use_stx'] == 1 && !empty($params['stx'])) {
$sfl_list = get_export_config('sfl_list');
$label = $sfl_list[$params['sfl']] ?? '';
$condition[] = "검색({$params['stx_cond']}) : {$label} - {$params['stx']}";
}
// 레벨 조건
if ($params['use_level'] == 1 && ($params['level_start'] || $params['level_end'])) {
$condition[] = "레벨: {$params['level_start']}~{$params['level_end']}";
}
// 가입일 조건
if ($params['use_date'] == 1 && ($params['date_start'] || $params['date_end'])) {
$condition[] = "가입일: {$params['date_start']}~{$params['date_end']}";
}
// 포인트 조건
if ($params['use_point'] == 1 && $params['point'] !== '') {
$point_cond_map = get_export_config('point_cond_map');
$symbol = $point_cond_map[$params['point_cond']] ?? '≥';
$condition[] = "포인트 {$symbol} {$params['point']}";
}
// 휴대폰 여부
if ($params['use_hp_exist'] == 1) {
$condition[] = "휴대폰번호 있는 경우만";
}
// 광고 수신 동의
if ($params['ad_range_only'] == 1) {
$ad_range_list = get_export_config('ad_range_list');
$label = $ad_range_list[$params['ad_range_type']] ?? '';
$condition[] = "수신동의: 예 ({$label})";
if ($params['ad_range_type'] == "custom_period" && ($params['agree_date_start'] || $params['agree_date_end'])) {
$condition[] = "수신동의일: {$params['agree_date_start']}~{$params['agree_date_end']}";
}
if (in_array($params['ad_range_type'], ["month_confirm", "custom_period"])){
$channels = array_filter([
!empty($params['ad_mailling']) && (int)$params['ad_mailling'] === 1 ? '이메일' : null,
!empty($params['ad_sms']) && (int)$params['ad_sms'] === 1 ? 'SMS/카카오톡' : null,
]);
if ($channels) {
$condition[] = '수신채널: ' . implode(', ', $channels);
}
}
}
// 차단회원 처리
if ($params['use_intercept'] == 1) {
$intercept_list = get_export_config('intercept_list');
$label = $intercept_list[$params['intercept']] ?? '';
if ($label) $condition[] = $label;
}
$conditionStr = !empty($condition) ? implode(', ', $condition) : '없음';
$line1 = "[{$datetime}] [{$status}] 관리자: {$username} | 형식: {$formatType}";
// 성공일 경우 추가 정보
if ($success) {
$total = $result['total'] ?? 0;
$fileCount = isset($result['zip']) ? 1 : count($result['files'] ?? []);
$line1 .= " | 총 {$total}건 | 파일: {$fileCount}";
}
$logEntry = $line1 . PHP_EOL;
$logEntry .= "조건: {$conditionStr}" . PHP_EOL;
if (!$success && !empty($result['error'])) {
$logEntry .= "오류 메시지: {$result['error']}" . PHP_EOL;
}
$logEntry .= PHP_EOL;
// 파일에 기록
if (@file_put_contents($latestLogFile, $logEntry, FILE_APPEND | LOCK_EX) === false) {
error_log("[Member Export Error] 로그 파일 기록 실패: {$latestLogFile}");
}
}

View File

@ -0,0 +1,72 @@
<?php
$sub_menu = '100930';
include_once('./_common.php');
if ($is_admin != 'super')
alert('최고관리자만 접근 가능합니다.', G5_URL);
$g5['title'] = '회원관리파일 일괄삭제';
include_once(G5_ADMIN_PATH.'/admin.head.php');
?>
<div class="local_desc02 local_desc">
<p>
완료 메세지가 나오기 전에 프로그램의 실행을 중지하지 마십시오.
</p>
</div>
<?php
flush();
if (!$dir = @opendir(G5_DATA_PATH . '/member_list')) {
echo '<p>회원관리파일를 열지못했습니다.</p>';
}
$cnt = 0;
echo '<ul class="session_del">' . PHP_EOL;
$files = glob(G5_DATA_PATH . '/member_list/*');
$cnt = 0;
// 폴더 및 하위 파일 재귀 삭제 함수
function deleteFolder($folderPath) {
$items = glob($folderPath . '/*');
foreach ($items as $item) {
if (is_dir($item)) {
deleteFolder($item);
} else {
unlink($item);
}
}
rmdir($folderPath); // 폴더 자체 삭제
}
if (is_array($files)) {
foreach ($files as $member_list_file) {
// log 확장자가 아닌 파일/디렉토리 처리
$ext = strtolower(pathinfo($member_list_file, PATHINFO_EXTENSION));
$basename = basename($member_list_file);
if (is_file($member_list_file) && $ext !== 'log') {
unlink($member_list_file);
echo '<li>파일 삭제: ' . $member_list_file . '</li>' . PHP_EOL;
$cnt++;
} elseif (is_dir($member_list_file) && $basename !== 'log') {
deleteFolder($member_list_file);
echo '<li>폴더 삭제: ' . $member_list_file . '</li>' . PHP_EOL;
$cnt++;
}
flush();
if ($cnt % 10 == 0) {
echo PHP_EOL;
}
}
}
echo '<li>완료됨</li></ul>' . PHP_EOL;
echo '<div class="local_desc01 local_desc"><p><strong>회원관리파일 ' . $cnt . '건 삭제 완료됐습니다.</strong><br>프로그램의 실행을 끝마치셔도 좋습니다.</p></div>' . PHP_EOL;
?>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');

View File

@ -27,6 +27,30 @@ if ($_POST['act_button'] == "선택수정") {
$post_mb_sms = isset($_POST['mb_sms'][$k]) ? (int) $_POST['mb_sms'][$k] : 0;
$post_mb_open = isset($_POST['mb_open'][$k]) ? (int) $_POST['mb_open'][$k] : 0;
$agree_items = [];
// 광고성 이메일 수신동의 일자 추가
$post_mb_mailling_default = isset($_POST['mb_mailling_default'][$k]) ? (int) $_POST['mb_mailling_default'][$k] : 0;
$sql_mailling_date = "";
if ($post_mb_mailling_default != $post_mb_mailling) {
$sql_mailling_date = " , mb_mailling_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "광고성 이메일 수신(" . ($post_mb_mailling == 1 ? "동의" : "철회") . ")";
}
// 광고성 SMS/카카오톡 수신동의 일자 추가
$post_mb_sms_default = isset($_POST['mb_sms_default'][$k]) ? (int) $_POST['mb_sms_default'][$k] : 0;
$sql_sms_date = "";
if ($post_mb_sms_default != $post_mb_sms) {
$sql_sms_date = " , mb_sms_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "광고성 SMS/카카오톡 수신(" . ($post_mb_sms == 1 ? "동의" : "철회") . ")";
}
// 동의 로그 추가
$sql_agree_log = "";
if (!empty($agree_items)) {
$agree_log = "[".G5_TIME_YMDHIS.", 회원관리 선택수정] " . implode(' | ', $agree_items) . "\n";
$sql_agree_log .= " , mb_agree_log = CONCAT('{$agree_log}', IFNULL(mb_agree_log, ''))";
}
$mb_datas[] = $mb = get_member($_POST['mb_id'][$k]);
if (!(isset($mb['mb_id']) && $mb['mb_id'])) {
@ -50,6 +74,9 @@ if ($_POST['act_button'] == "선택수정") {
mb_open = '" . $post_mb_open . "',
mb_certify = '" . sql_real_escape_string($post_mb_certify) . "',
mb_adult = '{$mb_adult}'
{$sql_mailling_date}
{$sql_sms_date}
{$sql_agree_log}
where mb_id = '" . sql_real_escape_string($mb['mb_id']) . "' ";
sql_query($sql);
}

View File

@ -32,6 +32,16 @@ include_once('./admin.head.php');
</ul>
</div>
<div class="service_2">
<div class="svc_ri svc_sms">
<div class="svc_a">
<h3>카카오톡 발송 서비스</h3>
<p>주문이나 배송시에 상점운영자 또는 고객에게 휴대폰으로 카카오톡을 발송합니다. <b>연동회원</b>으로 선택한 후 링크아이디 [<b>SIRSOFT</b>]를 입력해 주세요.</p>
</div>
<div class="svc_btn2"><a href="https://www.popbill.com/App/SignUp" target="_blank"><img src="<?php echo G5_ADMIN_URL ?>/img/svc_btn_07.jpg" alt="팝빌 카카오톡 서비스 신청하기"></a></div>
</div>
</div>
<div class="service_2">
<div class="svc_ri svc_sms">
<div class="svc_a">

View File

@ -680,9 +680,9 @@ $(function(){
</td>
</tr>
<tr>
<th scope="row"><label for="it_stock_sms">재입고SMS 알림</label></th>
<th scope="row"><label for="it_stock_sms">재입고 알림</label></th>
<td colspan="2">
<?php echo help("상품이 품절인 경우에 체크해 놓으면 상품상세보기에서 고객이 재입고SMS 알림을 신청할 수 있게 됩니다."); ?>
<?php echo help("상품이 품절인 경우에 체크해 놓으면 상품상세보기에서 고객이 재입고 알림(SMS/알림톡)을 신청할 수 있게 됩니다."); ?>
<input type="checkbox" name="it_stock_sms" value="1" id="it_stock_sms" <?php echo ($it['it_stock_sms']) ? "checked" : ""; ?>> 예
</td>
</tr>

View File

@ -4,7 +4,7 @@ include_once('./_common.php');
auth_check_menu($auth, $sub_menu, "r");
$g5['title'] = '재입고SMS 알림';
$g5['title'] = '재입고 알림';
include_once (G5_ADMIN_PATH.'/admin.head.php');
// 테이블 생성
@ -24,6 +24,12 @@ if(!sql_query(" select ss_id from {$g5['g5_shop_item_stocksms_table']} limit 1",
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ", true);
}
// 채널 구분 (1=SMS, 2=알림톡)
if(!sql_query(" select ss_channel from {$g5['g5_shop_item_stocksms_table']} limit 1", false)) {
sql_query(" ALTER TABLE `{$g5['g5_shop_item_stocksms_table']}`
ADD `ss_channel` tinyint(4) NOT NULL DEFAULT '1' AFTER `ss_ip` ", true);
}
$doc = isset($_GET['doc']) ? clean_xss_tags($_GET['doc'], 1, 1) : '';
$sort1 = (isset($_GET['sort1']) && in_array($_GET['sort1'], array('it_id', 'ss_hp', 'ss_send', 'ss_send_time', 'ss_datetime'))) ? $_GET['sort1'] : 'ss_send';
$sort2 = (isset($_GET['sort2']) && in_array($_GET['sort2'], array('desc', 'asc'))) ? $_GET['sort2'] : 'asc';
@ -109,8 +115,9 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
</th>
<th scope="col">상품명</th>
<th scope="col">휴대폰번호</th>
<th scope="col">SMS전송</th>
<th scope="col">SMS전송일시</th>
<th scope="col">전송결과</th>
<th scope="col">전송채널</th>
<th scope="col">전송일시</th>
<th scope="col">등록일시</th>
</tr>
</thead>
@ -139,13 +146,14 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
<td class="td_left"><?php echo $it_name; ?></td>
<td class="td_telbig"><?php echo $row['ss_hp']; ?></td>
<td class="td_stat"><?php echo ($row['ss_send'] ? '전송완료' : '전송전'); ?></td>
<td class="td_stat"><?php echo ($row['ss_send'] ? ($row['ss_channel'] == 2 ? " 알림톡" : " SMS") : ''); ?></td>
<td class="td_datetime"><?php echo (is_null_time($row['ss_send_time']) ? '' : $row['ss_send_time']); ?></td>
<td class="td_datetime"><?php echo (is_null_time($row['ss_datetime']) ? '' : $row['ss_datetime']); ?></td>
</tr>
<?php
}
if (!$i)
echo '<tr><td colspan="6" class="empty_table"><span>자료가 없습니다.</span></td></tr>';
echo '<tr><td colspan="7" class="empty_table"><span>자료가 없습니다.</span></td></tr>';
?>
</tbody>
</table>
@ -157,6 +165,10 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
<input type="submit" name="act_button" value="선택삭제" onclick="document.pressed=this.value" class="btn btn_02">
<?php } ?>
<input type="submit" name="act_button" value="선택SMS전송" class="btn_submit btn" onclick="document.pressed=this.value">
<?php if($config['cf_kakaotalk_use']) { ?>
<input type="submit" name="act_button" value="선택알림톡전송" class="btn_submit btn" onclick="document.pressed=this.value">
<?php } ?>
</div>
</form>
@ -170,13 +182,18 @@ function fitemstocksms_submit(f)
return false;
}
if(document.pressed == "선택삭제") {
if(!confirm("선택한 자료를 정말 삭제하시겠습니까?")) {
return false;
}
}
var action = document.pressed;
return true;
switch (action) {
case "선택삭제":
return confirm("선택한 자료를 정말 삭제하시겠습니까?");
case "선택SMS전송":
return confirm("선택한 자료에 대해서 SMS로 재입고 알림을 전송하시겠습니까?");
case "선택알림톡전송":
return confirm("선택한 자료에 대해서 알림톡으로 재입고 알림을 전송하시겠습니까?");
default:
return true;
}
}
</script>

View File

@ -45,7 +45,8 @@ if ($_POST['act_button'] == "선택SMS전송") {
// SMS 전송으로 변경함
$sql = " update {$g5['g5_shop_item_stocksms_table']}
set ss_send = '1',
ss_send_time = '".G5_TIME_YMDHIS."'
ss_send_time = '".G5_TIME_YMDHIS."',
ss_channel = '1'
where ss_id = '{$ss_id}' ";
sql_query($sql);
}
@ -98,6 +99,52 @@ if ($_POST['act_button'] == "선택SMS전송") {
$SMS->Init(); // 보관하고 있던 결과값을 지웁니다.
}
}
} else if ($_POST['act_button'] == "선택알림톡전송") {
// 알림톡 발송 BEGIN: 재입고알림(CU-ST01) -------------------------------------
auth_check_menu($auth, $sub_menu, 'w');
include_once(G5_KAKAO5_PATH.'/kakao5.lib.php');
if (!$config['cf_kakaotalk_use']) {
alert('카카오톡 사용 설정이 되어 있지 않아 발송할 수 없습니다.\n[환경설정>기본환경설정>기본알림환경]에서 사용 설정을 해주세요.');
} else {
// 프리셋 정보 가져오기
$alimtalk = get_alimtalk_preset_info('CU-ST01');
if (empty($alimtalk['success'])) {
alert('재입고 알림톡 설정이 되어 있지 않아 발송할 수 없습니다.\n[환경설정>알림톡프리셋 관리]에서 설정해주세요.');
} else {
for ($i=0; $i<$count_post_chk; $i++) {
// 실제 번호를 넘김
$k = isset($_POST['chk'][$i]) ? (int) $_POST['chk'][$i] : 0;
$ss_id = isset($_POST['ss_id'][$k]) ? (int) $_POST['ss_id'][$k] : 0;
$sql = " select a.ss_id, a.ss_hp, a.ss_send, b.it_id, b.it_name
from {$g5['g5_shop_item_stocksms_table']} a left join {$g5['g5_shop_item_table']} b on ( a.it_id = b.it_id )
where a.ss_id = '$ss_id' ";
$row = sql_fetch($sql);
if(!$row['ss_id'] || !$row['it_id'] || $row['ss_send'])
continue;
$conditions = ['it_id' => $row['it_id'], 'it_name' => get_text($row['it_name'])]; // 변수 치환 정보
$cu_atk = send_alimtalk_preset('CU-ST01', ['rcv' => $row['ss_hp']], $conditions); // 회원
// 성공한 건만 완료 처리
if (!empty($cu_atk) && !empty($cu_atk['success']))
{
sql_query(" update {$g5['g5_shop_item_stocksms_table']}
set ss_send = '1',
ss_send_time = '".G5_TIME_YMDHIS."',
ss_channel = '2'
where ss_id = '{$ss_id}' ");
}
}
}
}
// 알림톡 발송 END -------------------------------------------------------------
} else if ($_POST['act_button'] == "선택삭제") {
if ($is_admin != 'super')

View File

@ -0,0 +1,22 @@
<?php
if (!defined("_GNUBOARD_")) exit; // 개별 페이지 접근 불가
if (!defined("_ORDERALIMTALK_")) exit;
include_once(G5_KAKAO5_PATH.'/kakao5.lib.php');
$it_name_str = get_alimtalk_cart_item_name($od_id); // 상품명
// 입금 알림
if($od_alimtalk_ipgum_check){
// 알림톡 발송 BEGIN: 입금완료(CU-OR03 / AD-OR03) ------------------------------
$conditions = ['od_id' => $od_id, 'od_name' => $od_name, 'it_name' => $it_name_str]; // 변수 치환 정보
$cu_atk = send_alimtalk_preset('CU-OR03', ['rcv' => $od_hp ?: $od['od_tel'], 'rcvnm' => $od_name], $conditions); // 회원
// 알림톡 발송 END --------------------------------------------------------
}
// 배송 알림
if($od_alimtalk_baesong_check){
// 알림톡 발송 BEGIN: 배송중(CU-DE02) ------------------------------
$conditions = ['od_id' => $od_id, 'od_name' => $od_name, 'it_name' => $it_name_str]; // 변수 치환 정보
$cu_atk = send_alimtalk_preset('CU-DE02', ['rcv' => $od_hp ?: $od['od_tel'], 'rcvnm' => $od_name], $conditions); // 회원
// 알림톡 발송 END --------------------------------------------------------
}

View File

@ -3,6 +3,7 @@ $sub_menu = '400400';
include_once('./_common.php');
include_once('./admin.shop.lib.php');
include_once(G5_LIB_PATH.'/mailer.lib.php');
include_once(G5_KAKAO5_PATH.'/kakao5.lib.php');
auth_check_menu($auth, $sub_menu, "w");
@ -98,6 +99,14 @@ if(isset($_FILES['excelfile']['tmp_name']) && $_FILES['excelfile']['tmp_name'])
include(G5_SHOP_PATH.'/'.$od['od_pg'].'/escrow.register.php');
}
// 알림톡 발송 BEGIN: 배송중(CU-DE02/AD-DE02) ------------------------------
$it_name_str = get_alimtalk_cart_item_name($od_id); // 상품명
$conditions = ['od_id' => $od_id, 'od_name' => $od['od_name'], 'it_name' => $it_name_str]; // 변수 치환 정보
$cu_atk = send_alimtalk_preset('CU-DE02', ['rcv' => $od['od_hp'] ?: $od['od_tel'], 'rcvnm' => $od['od_name']], $conditions); // 회원
$ad_atk = send_admin_alimtalk('AD-DE02', 'super', $conditions); // 관리자
// 알림톡 발송 END --------------------------------------------------------
}
}

View File

@ -1,6 +1,7 @@
<?php
$sub_menu = '400400';
include_once('./_common.php');
include_once(G5_KAKAO5_PATH.'/kakao5.lib.php');
$cart_title3 = '주문번호';
$cart_title4 = '배송완료';
@ -282,6 +283,9 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<div class="local_desc01 local_desc">
<p>주문, 입금, 준비, 배송, 완료는 장바구니와 주문서 상태를 모두 변경하지만, 취소, 반품, 품절은 장바구니의 상태만 변경하며, 주문서 상태는 변경하지 않습니다.</p>
<p>개별적인(이곳에서의) 상태 변경은 모든 작업을 수동으로 처리합니다. 예를 들어 주문에서 입금으로 상태 변경시 입금액(결제금액)을 포함한 모든 정보는 수동 입력으로 처리하셔야 합니다.</p>
<?php if ($config['cf_kakaotalk_use']) { ?>
<p>* <b>알림톡 프리셋</b>: <b>[준비, 완료, 취소, 반품, 품절]</b>은 <b>자동</b>으로 발송되며, <b>[입금완료, 배송]</b>은 <b>결제상세정보에서 수동</b>으로 발송하셔야 합니다.</p>
<?php } ?>
</div>
</form>
@ -719,6 +723,16 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<label for="od_sms_ipgum_check">SMS 입금 문자전송</label>
<br>
<?php } ?>
<!-- 입금완료 알림톡 전송 -->
<?php
$alimtalk = get_alimtalk_preset_info('CU-OR03');
if ($config['cf_kakaotalk_use'] && isset($alimtalk['success'])) {?>
<input type="checkbox" name="od_alimtalk_ipgum_check" id="od_alimtalk_ipgum_check">
<label for="od_alimtalk_ipgum_check">입금완료 알림톡전송</label>
<br>
<?php } ?>
<input type="text" name="od_deposit_name" value="<?php echo get_text($od['od_deposit_name']); ?>" id="od_deposit_name" class="frm_input">
</td>
</tr>
@ -826,6 +840,17 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<label for="od_sms_baesong_check">SMS 배송 문자전송</label>
<br>
<?php } ?>
<!-- 배송 알림톡 전송 -->
<?php
$alimtalk = get_alimtalk_preset_info('CU-DE02');
if ($config['cf_kakaotalk_use'] && isset($alimtalk['success'])) {
?>
<input type="checkbox" name="od_alimtalk_baesong_check" id="od_alimtalk_baesong_check">
<label for="od_alimtalk_baesong_check">배송 알림톡전송</label>
<br>
<?php } ?>
<input type="text" name="od_invoice" value="<?php echo $od['od_invoice']; ?>" id="od_invoice" class="frm_input">
</td>
</tr>

View File

@ -1,6 +1,7 @@
<?php
$sub_menu = '400400';
include_once('./_common.php');
include_once(G5_KAKAO5_PATH.'/kakao5.lib.php');
auth_check_menu($auth, $sub_menu, "w");
@ -25,6 +26,7 @@ $sort2 = isset($_REQUEST['sort2']) ? clean_xss_tags($_REQUEST['sort2'], 1, 1) :
$sel_field = isset($_REQUEST['sel_field']) ? clean_xss_tags($_REQUEST['sel_field'], 1, 1) : '';
$mod_history = '';
$od_names = [];
$cnt = (isset($_POST['ct_id']) && is_array($_POST['ct_id'])) ? count($_POST['ct_id']) : 0;
$arr_it_id = array();
@ -155,6 +157,8 @@ for ($i=0; $i<$cnt; $i++)
// it_id를 배열에 저장
if($ct_status == '주문' || $ct_status == '취소' || $ct_status == '반품' || $ct_status == '품절' || $ct_status == '완료')
$arr_it_id[] = $ct['it_id'];
$od_names[] = $ct['it_name']; // 상품명 배열 : 알림톡 사용
}
// 상품 판매수량 반영
@ -375,7 +379,28 @@ $url = "./orderform.php?od_id=$od_id&amp;$qstr";
// 신용카드 취소 때 오류가 있으면 알림
if($pg_cancel == 1 && $pg_res_cd && $pg_res_msg) {
alert('오류코드 : '.$pg_res_cd.' 오류내용 : '.$pg_res_msg, $url);
} else {
} else {
// 알림톡 발송 BEGIN: 배송준비(DE01) | 배송완료(DE03) | 관리자 주문취소(OR05) | 반품처리(OR06) | 품절안내(OR07) ------------------------------
$alimtalk_map = [ '준비' => 'DE01', '완료' => 'DE03', '취소' => 'OR05', '반품' => 'OR06', '품절' => 'OR07' ]; // 알림톡 코드 매핑
// 처리상품명 및 치환 변수 값 세팅
$order = sql_fetch("select * from {$g5['g5_shop_order_table']} where od_id = '$od_id'"); // 주문 정보 조회
$it_name = !empty($od_names) ? $od_names[0] . (count($od_names) > 1 ? ' 외 ' . (count($od_names) - 1) . '건' : '') : ''; // 상품명
$conditions = [ 'od_id' => $od_id, 'it_name' => $it_name ]; // 변수 치환 정보
if (isset($alimtalk_map[$_POST['ct_status']])) {
$status_code = $alimtalk_map[$_POST['ct_status']];
// 고객 발송 (준비, 완료, 취소, 반품, 품절 공통)
$cu_atk = send_alimtalk_preset('CU-' . $status_code, ['rcv' => $order['od_hp'] ?: $order['od_tel'], 'rcvnm' => $order['od_name']], $conditions); // 회원
// 관리자 발송 (취소만)
if ($_POST['ct_status'] === '취소') {
$ad_atk = send_admin_alimtalk('AD-' . $status_code, 'super', $conditions); // 관리자
}
}
// 알림톡 발송 END -------------------------------------------------------------------------------------------------------------------
// 1.06.06
$od = sql_fetch(" select od_receipt_point from {$g5['g5_shop_order_table']} where od_id = '$od_id' ");
if ($od['od_receipt_point'])

View File

@ -161,6 +161,9 @@ include "./ordermail.inc.php";
define("_ORDERSMS_", true);
include "./ordersms.inc.php";
// 알림톡 전송 문자전송
define("_ORDERALIMTALK_", true);
include "./orderalimtalk.inc.php";
// 에스크로 배송처리
if($posts['od_tno'] && $posts['od_escrow'] == 1)

View File

@ -3,6 +3,7 @@ $sub_menu = '400400';
include_once('./_common.php');
include_once('./admin.shop.lib.php');
include_once(G5_LIB_PATH.'/mailer.lib.php');
include_once(G5_KAKAO5_PATH.'/kakao5.lib.php');
check_admin_token();
@ -48,6 +49,7 @@ for ($i=0; $i<$count_post_chk; $i++)
$current_status = $od['od_status'];
$change_status = isset($_POST['od_status']) ? clean_xss_tags($_POST['od_status'], 1, 1) : '';
$it_name_str = get_alimtalk_cart_item_name($od_id); // 상품명
switch ($current_status)
{
@ -69,6 +71,12 @@ for ($i=0; $i<$count_post_chk; $i++)
}
}
// 알림톡 발송 BEGIN: 입금완료(CU-OR03/AD-OR03) ------------------------------
$conditions = ['od_id' => $od_id, 'od_name' => $od['od_name'], 'it_name' => $it_name_str]; // 변수 치환 정보
$cu_atk = send_alimtalk_preset('CU-OR03', ['rcv' => $od['od_hp'] ?: $od['od_tel'], 'rcvnm' => $od['od_name']], $conditions); // 회원
$ad_atk = send_admin_alimtalk('AD-OR03', 'super', $conditions); // 관리자
// 알림톡 발송 END --------------------------------------------------------
// 메일
if($config['cf_email_use'] && $od_send_mail)
include './ordermail.inc.php';
@ -78,6 +86,12 @@ for ($i=0; $i<$count_post_chk; $i++)
case '입금' :
if ($change_status != '준비') continue 2;
change_status($od_id, '입금', '준비');
// 알림톡 발송 BEGIN: 배송준비(CU-DE01/AD-DE01) ------------------------------
$conditions = ['od_id' => $od_id, 'it_name' => $it_name_str]; // 변수 치환 정보
$cu_atk = send_alimtalk_preset('CU-DE01', ['rcv' => $od['od_hp'] ?: $od['od_tel'], 'rcvnm' => $od['od_name']], $conditions); // 회원
$ad_atk = send_admin_alimtalk('AD-DE01', 'super', $conditions); // 관리자
// 알림톡 발송 END -------------------------------------------------------------
break;
case '준비' :
@ -115,6 +129,11 @@ for ($i=0; $i<$count_post_chk; $i++)
include(G5_SHOP_PATH.'/'.$od['od_pg'].'/escrow.register.php');
}
// 알림톡 발송 BEGIN: 배송중(CU-DE02/AD-DE02) -------------------------------------
$conditions = ['od_id' => $od_id, 'it_name' => $it_name_str]; // 변수 치환 정보
$cu_atk = send_alimtalk_preset('CU-DE02', ['rcv' => $od['od_hp'] ?: $od['od_tel'], 'rcvnm' => $od['od_name']], $conditions); // 회원
$ad_atk = send_admin_alimtalk('AD-DE02', 'super', $conditions); // 관리자
// 알림톡 발송 END -------------------------------------------------------------
break;
case '배송' :
@ -139,6 +158,12 @@ for ($i=0; $i<$count_post_chk; $i++)
sql_query($sql3);
}
*/
// 알림톡 발송 BEGIN: 배송완료(CU-DE03/AD-DE03) -------------------------------------
$conditions = ['od_id' => $od_id, 'it_name' => $it_name_str]; // 변수 치환 정보
$cu_atk = send_alimtalk_preset('CU-DE03', ['rcv' => $od['od_hp'] ?: $od['od_tel'], 'rcvnm' => $od['od_name']], $conditions); // 회원
$ad_atk = send_admin_alimtalk('AD-DE03', 'super', $conditions); // 관리자
// 알림톡 발송 END -------------------------------------------------------------
break;
} // switch end