Compare commits

...

16 commits
v2.3.3 ... main

Author SHA1 Message Date
a82695bb4e
update 2025-12-07 01:55:12 +09:00
adf8c56665
fix 8.3 redis error, htmlprocess add features 2025-11-15 14:27:06 +09:00
98b6c95c89
patch-1 2025-09-18 09:53:20 +09:00
811436906d
wip 2025-02-26 16:11:58 +09:00
7a393e38b6
wip 2025-02-25 11:46:12 +09:00
5a69f51e86
update 2025-02-24 11:20:39 +09:00
3c89d9d77b
update 2025-02-10 02:01:08 +09:00
48adc55bdc
update 2025-02-10 01:53:49 +09:00
e6e2394d10
bump in-class version number 2025-01-28 18:31:07 +09:00
ec82e77e7d
add setting type 2025-01-28 18:27:41 +09:00
a73228fa09
update 2.3.4 for menulist 2025-01-17 02:44:12 +09:00
c115df4ebf
unlock maxlength fix 2024-11-22 01:13:33 +09:00
1e5e1ecf3d
unlock maxlength 2024-11-22 01:10:40 +09:00
d88c531b5b
fix condition group 2024-11-21 18:51:21 +09:00
df18afb6d4
add setting type 2024-11-20 17:31:37 +09:00
63ee22a3ad
admin page tail link update 2024-10-28 20:54:08 +09:00
100 changed files with 5893 additions and 1764 deletions

3
.gitignore vendored
View file

@ -62,3 +62,6 @@
error.log
access.log
build.log
net.json # for traffic
/net.json
[Aa]vocado[Aa]mber/net.json

3
AvocadoAmber/.htaccess Normal file
View file

@ -0,0 +1,3 @@
RewriteEngine On
RewriteRule ^(\.git|\.ht|\.travis|codeception\.|composer\.|Gruntfile\.js|package\.json|CONTRIBUTING|COPYRIGHT|LICENSE|README) - [L,F]

View file

@ -2,25 +2,82 @@
if (!defined('_GNUBOARD_'))
exit;
$font_sql = "SELECT * FROM {$g5['font_table']} ORDER BY font_name ASC";
$font_result = sql_query($font_sql);
function getFontCSSWithCache()
{
global $g5;
$cache_key = 'font_css_cache';
$cache_duration = 300;
echo "<style id=\"extra_font\">";
while ($row = sql_fetch_array($font_result)) {
if (USE_REDIS && class_exists('Redis')) {
try {
$redis = new Redis();
$redis->connect('localhost', 6379);
$cached_css = $redis->get($cache_key);
if ($cached_css !== false) {
$redis->close();
return $cached_css;
}
$css_content = generateFontCSS($g5);
$redis->setex($cache_key, $cache_duration, $css_content);
$redis->close();
return $css_content;
} catch (Exception $e) {
error_log("Redis 연결 실패: " . $e->getMessage());
}
}
return getFontCSSWithFileCache($g5, $cache_duration);
}
function getFontCSSWithFileCache($g5, $cache_duration)
{
$cache_file = G5_DATA_PATH . '/cache/font_css_cache.txt';
$cache_dir = dirname($cache_file);
if (!is_dir($cache_dir)) {
@mkdir($cache_dir, 0755, true);
}
if (file_exists($cache_file) && (time() - filemtime($cache_file)) < $cache_duration) {
return file_get_contents($cache_file);
}
$css_content = generateFontCSS($g5);
@file_put_contents($cache_file, $css_content, LOCK_EX);
return $css_content;
}
function generateFontCSS($g5)
{
$font_sql = "SELECT * FROM {$g5['font_table']} ORDER BY font_name ASC";
$font_result = sql_query($font_sql);
$css_content = "<style id=\"extra_font\">";
while ($row = sql_fetch_array($font_result)) {
$font_family = $row['font_family'];
$font_url = stripslashes($row['font_url']);
$font_weight = $row['font_weight'];
$font_style = $row['font_style'];
if (strpos($font_url, '@import') !== false) {
echo "{$font_url}\n\n";
$css_content .= "{$font_url}\n\n";
} else {
echo "@font-face {\n";
echo " font-family: '{$font_family}';\n";
echo " src: {$font_url};\n";
echo " font-weight: {$font_weight};\n";
echo " font-style: {$font_style};\n";
echo "}\n\n";
$css_content .= "@font-face {\n";
$css_content .= " font-family: '{$font_family}';\n";
$css_content .= " src: {$font_url};\n";
$css_content .= " font-weight: {$font_weight};\n";
$css_content .= " font-style: {$font_style};\n";
$css_content .= "}\n\n";
}
}
$css_content .= "</style>";
return $css_content;
}
echo "</style>";
echo getFontCSSWithCache();

View file

@ -0,0 +1,12 @@
<?php
if (!defined("_G5_ADMIN_")) {
exit;
}
$ext_table = [
"migrate" => G5_TABLE_PREFIX . "migrations"
];
if (!sql_table_exists($ext_table["migrate"])) {
}

View file

@ -38,15 +38,15 @@ $menu["config"]->getLastAddedMenu()->addSubFile("/design_form_update.php");
$menu["config"]->addChildMenu("config", "메인 편집", G5_ADMIN_URL . "/viewer_form.php", true, 400, "\F891", 0);
$menu["config"]->getLastAddedMenu()->addSubFile("/viewer_form_update.php");
$menu["config"]->addChildMenu("config", "홈페이지 폰트 설정", G5_ADMIN_URL . "/editor_font.php", true, 500, "\F5CB", 0);
$menu["config"]->getLastAddedMenu()->addSubFile("/editor_font_update.php");
$menu["config"]->addChildMenu("config", "홈페이지 폰트 설정", G5_ADMIN_URL . "/items/config/editor_font.php", true, 500, "\F5CB", 0);
$menu["config"]->getLastAddedMenu()->addSubFile("/items/config/editor_font_update.php");
$menu["config"]->addChildMenu("config", "메뉴 설정", G5_ADMIN_URL . "/menu_list.php", true, 600, "\F478", 0);
$menu["config"]->getLastAddedMenu()->addSubFile("/menu_list_update.php");
$menu["config"]->getLastAddedMenu()->addSubFile("/menu_form.php");
$menu["config"]->getLastAddedMenu()->addSubFile("/menu_form_search.php");
$menu["config"]->addChildMenu("config", "메뉴 설정", G5_ADMIN_URL . "/items/config/menu_list.php", true, 600, "\F478", 0);
$menu["config"]->getLastAddedMenu()->addSubFile("/items/config/menu_list_update.php");
$menu["config"]->getLastAddedMenu()->addSubFile("/items/config/menu_form.php");
$menu["config"]->getLastAddedMenu()->addSubFile("/items/config/menu_form_search.php");
$menu["config"]->addChildMenu("config", "애드온 설정", G5_ADMIN_URL . "/addon_config.php", true, 700, "\F4CA", 0);
$menu["config"]->addChildMenu("config", "애드온 설정", G5_ADMIN_URL . "/items/config/addon_config.php", true, 700, "\F4CA", 0);
$menu["config"]->addChildMenu("config", "홈페이지 상세관리", G5_ADMIN_URL . "/config_form.php", true, 1000, "\F3E5", 0);
$menu["config"]->getLastAddedMenu()->addSubFile("/config_form_update.php");

View file

@ -29,27 +29,27 @@ $menu["member"]->getLastAddedMenu()->addSubFile("/member_delete.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/member_list_update.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/member_list_delete.php");
$menu["member"]->addChildMenu("member", "접속자집계", G5_ADMIN_URL . "/visit_list.php", true, 200, "\F3F2", 0);
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_domain.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_browser.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_os.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_device.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_hour.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_date.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_week.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_month.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_year.php");
$menu["member"]->addChildMenu("member", "접속자집계", G5_ADMIN_URL . "/items/visitor/visit_list.php", true, 200, "\F3F2", 0);
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_domain.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_browser.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_os.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_device.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_hour.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_date.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_week.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_month.php");
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_year.php");
$menu["member"]->addChildMenu("member", "투표관리", G5_ADMIN_URL . "/poll_list.php", true, 500, "\F5F9", 0);
$menu["member"]->getLastAddedMenu()->addSubFile("/poll_form.php");
if ($config["cf_community"] && Community::isInitCommunity()) {
$menu["member"]->addChildMenu("member", "접속자검색", G5_ADMIN_URL . "/visit_search.php", true, 300, "\F52A", 0);
$menu["member"]->getLastAddedMenu()->addSubFile("/visit_delete_update.php");
$menu["member"]->addChildMenu("member", "접속자검색", G5_ADMIN_URL . "/items/visitor/visit_search.php", true, 300, "\F52A", 0);
$menu["member"]->getLastAddedMenu()->addSubFile("/items/visitor/visit_delete_update.php");
$menu["member"]->addChildMenu("member", "캐릭터 미등록 회원관리", G5_ADMIN_URL . "/member_nocharacter_list.php", true, 400, "\F35E", 0);
$menu["member"]->getLastAddedMenu()->addSubFile("/member_nocharacter_list_update.php");
$menu["member"]->addChildMenu("member", "활동량 관리", G5_ADMIN_URL . "/action_list.php", true, 410, "\F809", 0);
$menu["member"]->getLastAddedMenu()->addSubFile("/action_reply.php");
$menu["member"]->addChildMenu("member", "활동량 관리", G5_ADMIN_URL . "/items/action/index.php", true, 410, "\F809", 0);
$menu["member"]->getLastAddedMenu()->addSubFile("/items/action/action_reply.php");
}

View file

@ -30,6 +30,8 @@ $menu["content"]->getLastAddedMenu()->addSubFile("/board_form_update.php");
$menu["content"]->getLastAddedMenu()->addSubFile("/board_delete.php");
$menu["content"]->getLastAddedMenu()->addSubFile("/board_copy.php");
$menu["content"]->getLastAddedMenu()->addSubFile("/board_copy_update.php");
$menu["content"]->getLastAddedMenu()->addSubFile("/board_move_list.php");
$menu["content"]->getLastAddedMenu()->addSubFile("/board_move_check.php");
$menu["content"]->addChildMenu("content", "게시판그룹관리", G5_ADMIN_URL . "/boardgroup_list.php", true, 100, "\F2EE", 0);
$menu["content"]->getLastAddedMenu()->addSubFile("/boardgroup_list_update.php");

View file

@ -1,107 +0,0 @@
<?php
include_once __DIR__ . '/_common.php';
include_once G5_EDITOR_LIB;
if ($is_admin != 'super') {
alert_close('최고관리자만 접근 가능합니다.');
}
if (!sql_fetch_array(sql_query("DESC {$g5['addons_config_table']}"))) {
sql_query("CREATE TABLE {$g5['addons_config_table']} (
addon_name VARCHAR(255) PRIMARY KEY,
addon_version VARCHAR(255),
addon_config TEXT
);");
}
$g5['title'] = "애드온 설정";
include_once __DIR__ . '/admin.head.php';
add_stylesheet(get_embed_file("css", G5_PATH . "/adm/css/addon_config.css"), 1);
?>
<section class="addon_config">
<nav><span>설치된 애드온 목록</span><?php
if (!empty(AddonLoader::$addons)) {
foreach (AddonLoader::$addons as $menu) {
$selected = isset($_GET["addon"]) && $_GET["addon"] == $menu->className ? " selected" : "";
echo "<a href=\"./addon_config.php?addon={$menu->className}\" class=\"addon_menu{$selected}\">{$menu->name}</a>";
}
} else {
echo "<a href=\"#\">설치된 애드온이 없습니다.</a>";
}
?></nav>
<section>
<?php
if (isset($_GET["addon"])) {
if (array_key_exists($_GET["addon"], AddonLoader::$addons)) {
$addon = AddonLoader::$addons[$addon];
?>
<header>
<div class="tbl_frm01 tbl_wrap">
<table>
<colgroup>
<col style="width: 140px;">
<col>
</colgroup>
<tbody>
<tr>
<th scope="row">
애드온 이름
</th>
<td>
<?= $addon->name ?>
</td>
</tr>
<tr>
<th scope="row">
애드온 제작자
</th>
<td>
<?= $addon->link ? "<a href=\"" . $addon->link . "\" target=\"_blank\">" . $addon->author . "</a> <span style=\"font-size: 11px\">[{$addon->link}]</span>" : $addon->author ?>
</td>
</tr>
<tr>
<th scope="row">
애드온 설명
</th>
<td>
<?= $addon->description ?>
</td>
</tr>
<tr>
<th scope="row">
애드온 버전
</th>
<td>
<?= $addon->version ?>
</td>
</tr>
</tbody>
</table>
</div>
</header>
<content>
<form method="POST" action="./addon_config_update.php">
<input type="hidden" name="addon" value="<?= $addon->className ?>" />
<?php
if (method_exists($addon, "printConfigForm")) {
$addon->printConfigForm();
}
?>
<div class="btn_confirm">
<div class="btn">
<span class="material-icons">save</span>
<input type="submit" value="저장" class="btn_submit" accesskey="s">
</div>
</div>
</form>
</content><?php
}
} else {
echo "<span class=\"empty\">애드온을 선택하세요</span>";
}
?>
</section>
</section>
<?php
include_once __DIR__ . '/admin.tail.php';

View file

@ -0,0 +1,402 @@
<?php
if (!defined('_GNUBOARD_'))
exit;
// todo
function getDefaultForm($method, $url)
{
}
function initCheckNeedUpdate()
{
if (!defined('ADM_LISTEDIT_SCRIPTS_ADDED')) {
define('ADM_LISTEDIT_SCRIPTS_ADDED', true);
// 스크립트 추가
$scripts = "
<script>
function addListItem(containerId, placeholder) {
var container = document.getElementById(containerId);
var newItem = document.createElement('div');
var adder = document.getElementById(`\${containerId}_new`);
var content = adder?.value;
newItem.className = 'adm-listedit-item';
newItem.innerHTML = '<input type=\"text\" value=\"' + content + '\" placeholder=\"' + placeholder + '\">' +
'<button type=\"button\" class=\"adm-listedit-remove\" onclick=\"removeListItem(this)\">삭제</button>';
container.appendChild(newItem);
adder.value = '';
var newInput = newItem.querySelector('input[type=\"text\"]');
var optionKey = containerId.replace('_items', '');
newInput.addEventListener('input', function() {
updateListHiddenInput(optionKey);
});
// Enter 키 이벤트 추가
newInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.keyCode === 13) {
e.preventDefault();
var placeholder = newInput.getAttribute('placeholder');
addListItem(containerId, placeholder);
}
});
// 포커스를 새로 추가된 입력 필드에 설정
adder.focus();
updateListHiddenInput(optionKey);
}
function removeListItem(button) {
var item = button.parentElement;
var container = item.parentElement;
var optionKey = container.id.replace('_items', '');
// 최소 하나의 입력 필드는 유지 (추가 버튼 제외)
var inputItems = container.querySelectorAll('.adm-listedit-item:not(.adm-listedit-add-row)');
if (inputItems.length > 1) {
item.remove ? item.remove() : item.parentNode.removeChild(item);
} else {
// 마지막 항목인 경우 입력값만 비우기
var input = item.querySelector('input[type=\"text\"]');
input.value = '';
}
updateListHiddenInput(optionKey);
}
function updateListHiddenInput(optionKey) {
var container = document.getElementById(optionKey + '_items');
var listContainer = document.getElementById(optionKey + '_container');
var separator = listContainer.getAttribute('data-separator');
var inputs = container.querySelectorAll('input[type=\"text\"]');
var values = [];
for (var i = 0; i < inputs.length; i++) {
var value = inputs[i].value.trim();
if (value) {
values.push(value);
}
}
var hiddenInput = document.getElementById(optionKey + '_hidden');
hiddenInput.value = values.join(separator);
}
// DOM 로드 후 이벤트 리스너 설정
function initializeListEdit() {
var containers = document.querySelectorAll('.adm-listedit-items');
for (var i = 0; i < containers.length; i++) {
var container = containers[i];
var optionKey = container.id.replace('_items', '');
var inputs = container.querySelectorAll('input[type=\"text\"]');
for (var j = 0; j < inputs.length; j++) {
var input = inputs[j];
(function(inp, key) {
inp.addEventListener('input', function() {
updateListHiddenInput(key);
});
})(input, optionKey);
}
// 새 입력칸에 Enter 키 이벤트 추가
var newInput = document.getElementById(optionKey + '_new_input');
if (newInput) {
newInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.keyCode === 13) {
e.preventDefault();
var optKey = this.id.replace('_new_input', '');
addListItemFromInput(optKey);
}
});
}
}
// 폼 제출 전에 한 번 더 업데이트
var forms = document.querySelectorAll('form');
for (var k = 0; k < forms.length; k++) {
forms[k].addEventListener('submit', function() {
for (var l = 0; l < containers.length; l++) {
var container = containers[l];
var optionKey = container.id.replace('_items', '');
updateListHiddenInput(optionKey);
}
});
}
}
// DOM 로드 완료 시 초기화
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeListEdit);
} else {
initializeListEdit();
}
</script>";
add_javascript($scripts, 10);
}
}
function getCurrentValue($key, $value)
{
initCheckNeedUpdate();
return is_array($value) ? ( isset($value[$key]) ? $value[$key] : "" ) : $value;
}
function getSkinDir($skin, $skin_path = G5_SKIN_PATH)
{
global $g5;
$result_array = [];
$dirname = implode(DIRECTORY_SEPARATOR, [$skin_path, $skin, ""]);
if (!is_dir($dirname))
return;
$handle = opendir($dirname);
while ($file = readdir($handle)) {
if ($file == '.' || $file == '..')
continue;
if (is_dir($dirname . $file))
$result_array[$file] = $file;
}
closedir($handle);
sort($result_array);
return $result_array;
}
function getSkinList($skin_type)
{
global $config;
$skins = [];
if (defined('G5_THEME_PATH') && $config['cf_theme']) {
$dirs = getSkinDir($skin_type, G5_THEME_PATH . '/' . G5_SKIN_DIR);
if (!empty($dirs)) {
foreach ($dirs as $dir) {
$skins[$dir] = "theme/{$dir}";
}
}
}
$ret = [];
$dir = array_merge($skins, getSkinDir($skin_type));
foreach($dir as $k => $v) {
$ret[$v] = $v;
}
return $ret;
}
function getMemberLevels($include_admin = false)
{
global $g5;
$level_name[1] = "방문자";
$level_name[2] = "멤버";
$level_name[3] = "상위멤버";
if ($include_admin) $level_name[10] = "운영자";
return $level_name;
}
function setCheckbox($optionName, $optionDesc, $optionKey, $optionValue, $currentValue, $standalone = false)
{
$currentValue = getCurrentValue($optionKey, $currentValue);
$checked = "";
$v = "";
$desc = $optionDesc ? "<div class=\"adm-form-desc\">{$optionDesc}</div>" : "";
if ($currentValue) $checked = " checked";
if ($standalone) $v .= "<form>";
$v .= '<div class="adm-form adm-form-colflex">';
$v .= "<div class=\"adm-form-flex-full\"><div class=\"adm-form-name\">{$optionName}</div>{$desc}</div>";
$v .= '<div class="adm-form-input">';
$v .= "<div class=\"adm-form-check\"><input type=\"checkbox\" name=\"{$optionKey}\" value=\"{$optionValue}\"{$checked}><div class=\"adm-form-checkbox-cover\"></div></div>";
$v .= '</div></div>';
if ($standalone) $v .= "</form>";
echo $v;
}
function setNumberInput($optionName, $optionDesc, $optionKey, $currentValue, $preDesc = "", $postDesc = "", $minValue = 0, $maxValue = 0, $standalone = false)
{
$currentValue = getCurrentValue($optionKey, $currentValue);
$v = "";
$min = $minValue ? " min=\"{$minValue}\"" : "";
$max = $maxValue ? " max=\"{$maxValue}\"" : "";
$desc = $optionDesc ? "<div class=\"adm-form-desc\">{$optionDesc}</div>" : "";
if ($standalone) $v .= "<form>";
$v .= "<div class=\"adm-form adm-form-colflex\">
<div class=\"adm-form-flex-full\">
<div class=\"adm-form-name\">{$optionName}</div>{$desc}
</div>
<div class=\"adm-form-input\">
<div class=\"adm-form-number\">
<span class=\"adm-form-prefix\">{$preDesc}</span>
<input type=\"number\" name=\"{$optionKey}\" value=\"{$currentValue}\"{$min}{$max}>
<span class=\"adm-form-postfix\">{$postDesc}</span>
</div>
</div>
</div>";
if ($standalone) $v .= "</form>";
echo $v;
}
function setTextInput($optionName, $optionDesc, $optionKey, $currentValue, $standalone = false)
{
$currentValue = getCurrentValue($optionKey, $currentValue);
$v = "";
$desc = $optionDesc ? "<div class=\"adm-form-desc\">{$optionDesc}</div>" : "";
if ($standalone) $v .= "<form>";
$v .= '<div class="adm-form adm-form-rowflex">';
$v .= "<div class=\"adm-form-flex-full\"><div class=\"adm-form-name\">{$optionName}</div>{$desc}</div>";
$v .= '<div class="adm-form-input">';
$v .= "<div class=\"adm-form-text\"><input type=\"text\" name=\"{$optionKey}\" value=\"{$currentValue}\"></div>";
$v .= '</div></div>';
if ($standalone) $v .= "</form>";
echo $v;
}
function setAccountList($optionName, $optionDesc, $level, $optionKey, $optionValue, $currentValue, $required = false, $standalone = false)
{
global $g5;
$sql = "SELECT mb_id, mb_nick FROM {$g5['member_table']} WHERE mb_level >= '{$level}' ";
$required_option = $required ? " required" : "";
$currentValue = getCurrentValue($optionKey, $currentValue);
$v = "";
$desc = $optionDesc ? "<div class=\"adm-form-desc\">{$optionDesc}</div>" : "";
$result = sql_query($sql);
if ($standalone) $v .= "<form>";
$v .= '<div class="adm-form adm-form-rowflex">';
$v .= "<div class=\"adm-form-flex-full\"><div class=\"adm-form-name\">{$optionName}</div>{$desc}</div>";
$v .= '<div class="adm-form-input">';
$v .= "<div class=\"adm-form-select\"><select id=\"{$optionKey}\" name=\"{$optionKey}\"{$required_option}><option value=\"\">미선택</option>";
for ($i = 0; $row = sql_fetch_array($result); $i++) {
$selected = $row['mb_id'] == $currentValue ? " selected" : "";
$v .= "<option value=\"{$row['mb_id']}\"{$selected}>{$row['mb_nick']} ({$row['mb_id']})</option>";
}
$v .= "</select></div>";
$v .= '</div></div>';
if ($standalone) $v .= "</form>";
echo $v;
}
function setOptionList($optionName, $optionDesc, $optionListObject, $optionKey, $optionValue, $currentValue, $required = false, $standalone = false)
{
global $g5;
$required_option = $required ? " required" : "";
$currentValue = getCurrentValue($optionKey, $currentValue);
$v = "";
$desc = $optionDesc ? "<div class=\"adm-form-desc\">{$optionDesc}</div>" : "";
if ($standalone) $v .= "<form>";
$v .= "<div class=\"adm-form adm-form-rowflex\">
<div class=\"adm-form-flex-full\">
<div class=\"adm-form-name\">{$optionName}</div>{$desc}
</div>
<div class=\"adm-form-input\">
<div class=\"adm-form-select\">
<select id=\"{$optionKey}\" name=\"{$optionKey}\"{$required_option}>";
foreach($optionListObject as $val => $text) {
$selected = $val == $currentValue ? " selected" : "";
$v .= " <option value=\"{$val}\"{$selected}>{$text}</option>";
}
$v .= " </select>
</div>
</div>
</div>";
if ($standalone) $v .= "</form>";
echo $v;
}
function setImageFile($optionName, $optionDesc, $optionKey, $currentValue, $standalone = false)
{
$currentValue = getCurrentValue($optionKey, $currentValue);
$v = "";
$desc = $optionDesc ? "<div class=\"adm-form-desc\">{$optionDesc}<br>파일을 선택하거나 주소를 입력하여 등록할 수 있습니다. 주소 입력을 비워두면 설정이 해제됩니다.</div>" : "";
if ($standalone) $v .= "<form>";
$v .= "<div class=\"adm-form adm-form-rowflex\">
<div class=\"adm-form-flex-full\">
<div class=\"adm-form-name\">{$optionName}</div>{$desc}
</div>
<div class=\"adm-form-input\">
<div class=\"adm-form-file\">
<div class=\"adm-form-fileinput\">
<span>직접 선택</span>
<input type=\"file\" name=\"{$optionKey}_file\" value=\"\">
</div>
<div class=\"adm-form-filetext\">
<span>파일 URL</span>
<input type=\"text\" name=\"{$optionKey}\" value=\"{$currentValue}\">
</div>
</div>
</div>
</div>";
if ($standalone) $v .= "</form>";
echo $v;
}
function setListEditInput($optionName, $optionDesc, $optionKey, $currentValue, $separator = "\n", $placeholder = "", $standalone = false)
{
$currentValue = getCurrentValue($optionKey, $currentValue);
$v = "";
$desc = $optionDesc ? "<div class=\"adm-form-desc\">{$optionDesc}</div>" : "";
$itemList = [];
if (!empty($currentValue)) {
$itemList = array_filter(array_map('trim', explode($separator, $currentValue)));
}
$jsSeparator = addslashes($separator);
if ($standalone) $v .= "<form>";
$v .= "<div class=\"adm-form adm-form-rowflex\">
<div class=\"adm-form-flex-full\">
<div class=\"adm-form-name\">{$optionName}</div>{$desc}
</div>
<div class=\"adm-form-input\">
<div class=\"adm-form-listedit\" id=\"{$optionKey}_container\" data-separator=\"{$jsSeparator}\">
<div class=\"adm-listedit-items\" id=\"{$optionKey}_items\">";
if (!empty($itemList)) {
foreach ($itemList as $index => $item) {
$v .= "
<div class=\"adm-listedit-item\">
<input type=\"text\" value=\"" . htmlspecialchars($item) . "\" placeholder=\"{$placeholder}\">
<button type=\"button\" class=\"adm-listedit-remove\" onclick=\"removeListItem(this)\">삭제</button>
</div>";
}
}
$v .= "
</div>
<div class=\"adm-listedit-controls\">
<input type=\"text\" id=\"{$optionKey}_items_new\" value=\"\" placeholder=\"{$placeholder}\">
<button type=\"button\" class=\"adm-listedit-add\" onclick=\"addListItem('{$optionKey}_items', '{$placeholder}')\">추가</button>
</div>
<input type=\"hidden\" name=\"{$optionKey}\" id=\"{$optionKey}_hidden\" value=\"" . htmlspecialchars($currentValue) . "\">
</div>
</div>
</div>";
if ($standalone) $v .= "</form>";
echo $v;
}

View file

@ -31,15 +31,15 @@ include_once G5_PATH . '/head.sub.php';
<header id="header">
<div id="admin_prof">
<h1>
<a href="<?php echo G5_ADMIN_URL ?>"><img src="<?= G5_ADMIN_URL ?>/img/logo.png" alt="Avocado Edition" /></a>
<a href="<?php echo G5_ADMIN_URL ?>"><img src="<?= G5_ADMIN_URL ?>/img/logo.png" alt="Avocado Edition: Amber" /></a>
</h1>
</div>
<p>
<a href="<?php echo G5_ADMIN_URL ?>/member_form.php?w=u&amp;mb_id=<?php echo $member['mb_id'] ?>" class="name">
<?= $member['mb_name'] ?>
</a>
<a href="<?php echo G5_BBS_URL ?>/logout.php" class="logout">로그아웃</a>
</p>
</div>
<nav id="gnb">
<ul>
<li style="border-bottom:1px solid #444;">
@ -65,6 +65,7 @@ include_once G5_PATH . '/head.sub.php';
</nav>
</header>
<section id="wrapper">
<div class="admin-content">
<aside id="page_top">
<h2><?php echo $g5['title'] ?></h2>
</aside>

View file

@ -2,6 +2,8 @@
if (!defined('_GNUBOARD_'))
exit;
include_once "./admin.amber.lib.php";
function get_skin_select($skin_gubun, $id, $name, $selected = '', $event = '')
{
global $config;

View file

@ -2,8 +2,9 @@
if (!defined('_GNUBOARD_'))
exit;
?>
</div>
<div class="footer-copyright">
<a href="https://amberst.one/amber/AvocadoAmber"> Avocado Amber v<?= G5_GNUBOARD_VER ?> </a>
<a href="https://amberst.one/amber/AvocadoAmber" target="_blank"> Avocado Amber v<?= G5_GNUBOARD_VER ?> </a>
</div>
</section>
</div>
@ -11,6 +12,17 @@ if (!defined('_GNUBOARD_'))
<script src="<?php echo G5_ADMIN_URL ?>/js/admin.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo G5_ADMIN_URL ?>/js/admin.ajax.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script>
// give section active class
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('section[id^=anc_]').forEach((section) => {
let section_id = section.getAttribute('id');
if (section_id) {
let anc = section.querySelector(`a[href='#${section_id}']`);
anc.classList.add('active');
}
});
});
$(function () {
var hide_menu = false;
var mouse_event = false;

View file

@ -9,7 +9,8 @@ CREATE TABLE `__TABLE_NAME__` (
`ca_name` varchar(255) NOT NULL,
`wr_option` set('html1','html2','secret','mail') NOT NULL,
`wr_subject` varchar(255) NOT NULL,
`wr_content` text NOT NULL,
`wr_content` mediumtext NOT NULL,
`wr_extra_vars` text NOT NULL,
`wr_link1` text NOT NULL,
`wr_link2` text NOT NULL,
`wr_link1_hit` int(11) NOT NULL DEFAULT '0',
@ -19,6 +20,7 @@ CREATE TABLE `__TABLE_NAME__` (
`wr_nogood` int(11) NOT NULL DEFAULT '0',
`mb_id` varchar(20) NOT NULL,
`wr_password` varchar(255) NOT NULL,
`wr_extrapassword` varchar(255) NOT NULL,
`wr_name` varchar(255) NOT NULL,
`wr_email` varchar(255) NOT NULL,
`wr_homepage` varchar(255) NOT NULL,

View file

@ -99,8 +99,10 @@
* @var string|int $bo_8
* @var string|int $bo_9
* @var string|int $bo_10
* @var string $bo_version
*/
include_once "./_common.php";
include_once "./board_migration.inc.php";
if ($w == 'u')
check_demo();
@ -263,7 +265,8 @@ $sql_common = " gr_id = '{$_POST['gr_id']}',
bo_7 = '{$_POST['bo_7']}',
bo_8 = '{$_POST['bo_8']}',
bo_9 = '{$_POST['bo_9']}',
bo_10 = '{$_POST['bo_10']}' ";
bo_10 = '{$_POST['bo_10']}',
bo_version = '". BOARD_MIGRATION_VERSION . "'";
if ($w == '') {
@ -317,12 +320,6 @@ if ($w == '') {
$sql = "SELECT a.wr_id, (count(b.wr_parent) - 1) AS cnt FROM {$g5['write_prefix']}{$bo_table} a, {$g5['write_prefix']}{$bo_table} b WHERE a.wr_id=b.wr_parent AND a.wr_is_comment=0 GROUP BY a.wr_id ";
$result = sql_query($sql);
for ($i = 0; $row = sql_fetch_array($result); $i++) {
/*
// 코멘트수를 얻습니다.
$sql2 = "SELECT count(*) as cnt FROM {$g5['write_prefix']}$bo_table where wr_parent = '{$row['wr_id']}' and wr_is_comment = 1 ";
$row2 = sql_fetch($sql2);
*/
sql_query("UPDATE {$g5['write_prefix']}{$bo_table} SET wr_comment = '{$row['cnt']}' where wr_id = '{$row['wr_id']}' ");
}
}
@ -352,7 +349,6 @@ if ($w == '') {
}
// 같은 그룹내 게시판 동일 옵션 적용
$grp_fields = '';
if (is_checked('chk_grp_device'))

View file

@ -1,8 +1,12 @@
<?php
include_once "./_common.php";
include_once "./board_migration.inc.php";
auth_check($auth[$sub_menu], 'r');
// 마이그레이션 체크
$boards_need_update = check_all_boards_migration();
$sql_common = " from {$g5['board_table']} a ";
$sql_search = " where (1) ";
@ -66,6 +70,11 @@ $colspan = 11;
<div class="local_ov01 local_ov">
<?php echo $listall ?>
생성된 게시판수 <?php echo number_format($total_count) ?>
<?php if (count($boards_need_update) > 0) { ?>
<span style="font-weight: bold; margin-left: 20px;">
업데이트 필요: <?php echo count($boards_need_update) ?>
</span>
<?php } ?>
</div>
<form name="fsearch" id="fsearch" class="local_sch01 local_sch" method="get">
@ -111,7 +120,8 @@ $colspan = 11;
<th scope="col" style="width:80px;">글쓰기</th>
<th scope="col" style="width:80px;">글답변</th>
<th scope="col" style="width:80px;">댓글쓰기</th>
<th scope="col" style="width:60px;">관리</th>
<th scope="col" style="width:80px;">버전</th>
<th scope="col" style="width:150px;">관리</th>
</tr>
</thead>
<tbody>
@ -119,6 +129,16 @@ $colspan = 11;
for ($i = 0; $row = sql_fetch_array($result); $i++) {
$one_update = '<a href="./board_form.php?w=u&amp;bo_table=' . $row['bo_table'] . '&amp;' . $qstr . '">수정</a>';
$one_copy = '<a href="./board_copy.php?bo_table=' . $row['bo_table'] . '" class="board_copy" target="win_board_copy">복사</a>';
$s_move = '<a href="./board_move_list.php?bo_table=' . $row['bo_table'] . '">게시물이동</a>';
// 마이그레이션 필요 여부 체크
$need_migration = false;
foreach ($boards_need_update as $board_update) {
if ($board_update['bo_table'] == $row['bo_table']) {
$need_migration = true;
break;
}
}
$bg = 'bg' . ($i % 2);
?>
@ -163,14 +183,27 @@ $colspan = 11;
<?php echo get_member_level_select('bo_comment_level[' . $i . ']', 1, 10, $row['bo_comment_level']) ?>
</td>
<td>
<?php if ($need_migration) { ?>
<span style="color: #ff6b6b; font-weight: bold;">업데이트 필요</span>
<?php } else { ?>
<span><?php echo htmlspecialchars($row['bo_version']); ?></span>
<?php } ?>
</td>
<td>
<div class="manage_buttons">
<?php echo $one_update ?>
<?php echo $one_copy ?>
<?php echo $s_move ?>
<?php if ($need_migration) { ?>
<br><a href="#" class="btn_migrate" data-bo-table="<?php echo $row['bo_table'] ?>">업데이트</a>
<?php } ?>
</div>
</td>
</tr>
<?php
}
if ($i == 0)
echo '<tr><td colspan="' . $colspan . '" class="empty_table">자료가 없습니다.</td></tr>';
echo '<tr><td colspan="' . ($colspan + 1) . '" class="empty_table">자료가 없습니다.</td></tr>';
?>
</tbody>
</table>
@ -186,6 +219,12 @@ $colspan = 11;
<span class="material-icons">delete</span>
<input type="submit" name="act_button" value="선택삭제" title="선택삭제" onclick="document.pressed=this.value">
</div>
<?php if (count($boards_need_update) > 0) { ?>
<div class="btn ty4">
<span class="material-icons">update</span>
<input type="submit" name="act_button" value="선택마이그레이션" title="선택마이그레이션" onclick="document.pressed=this.value">
</div>
<?php } ?>
<?php if ($is_admin == 'super') { ?>
<a href="./board_form.php" title="게시판 추가" class="btn"><span class="material-icons">add</span></a>
<?php } ?>
@ -208,6 +247,12 @@ $colspan = 11;
}
}
if (document.pressed == "선택마이그레이션") {
if (!confirm("선택한 게시판을 마이그레이션 하시겠습니까?")) {
return false;
}
}
return true;
}
@ -216,6 +261,36 @@ $colspan = 11;
window.open(this.href, "win_board_copy", "left=100,top=100,width=550,height=450");
return false;
});
$(".btn_migrate").click(function (e) {
e.preventDefault();
var bo_table = $(this).data('bo-table');
if (!confirm(bo_table + ' 게시판을 업데이트 하시겠습니까?')) {
return false;
}
$.ajax({
url: './board_list_update.php',
type: 'POST',
data: {
act_button: '단일마이그레이션',
bo_table: bo_table,
token: '<?php echo $token ?>'
},
dataType: 'json',
success: function (response) {
if (response.success) {
location.reload();
} else {
alert('오류: ' + response.message);
}
},
error: function () {
alert('마이그레이션 중 오류가 발생했습니다.');
}
});
});
});
</script>

View file

@ -1,13 +1,63 @@
<?php
include_once "./_common.php";
include_once "./board_migration.inc.php";
check_demo();
// 단일 마이그레이션 처리 (AJAX)
if ($_POST['act_button'] == "단일마이그레이션") {
header('Content-Type: application/json');
auth_check($auth[$sub_menu], 'w');
$bo_table = sql_real_escape_string(strip_tags($_POST['bo_table']));
if (empty($bo_table)) {
echo json_encode(['success' => false, 'message' => '게시판 테이블명이 없습니다.']);
exit;
}
$result = migrate_board_table($bo_table);
echo json_encode($result);
exit;
}
// 선택 마이그레이션 처리
if (!count($_POST['chk'])) {
alert($_POST['act_button'] . " 하실 항목을 하나 이상 체크하세요.");
}
if ($_POST['act_button'] == "선택수정") {
if ($_POST['act_button'] == "선택마이그레이션") {
auth_check($auth[$sub_menu], 'w');
if (!count($_POST['chk'])) {
alert("마이그레이션 하실 항목을 하나 이상 체크하세요.");
}
$success_count = 0;
$fail_count = 0;
$messages = [];
for ($i = 0; $i < count($_POST['chk']); $i++) {
$k = $_POST['chk'][$i];
$bo_table = sql_real_escape_string(strip_tags($_POST['board_table'][$k]));
if (empty($bo_table)) {
continue;
}
$result = migrate_board_table($bo_table);
if ($result['success']) {
$success_count++;
$messages[] = "{$bo_table}: 성공 (컬럼 {$result['updated']}개 추가)";
} else {
$fail_count++;
$messages[] = "{$bo_table}: 실패 - {$result['message']}";
}
}
} else if ($_POST['act_button'] == "선택수정") {
auth_check($auth[$sub_menu], 'w');
@ -28,7 +78,7 @@ if ($_POST['act_button'] == "선택수정") {
$purify_keys = ["gr_id", "bo_subject", "bo_skin", "bo_list_level", "bo_read_level", "bo_write_level", "bo_comment_level", "bo_reply_level", "board_table"];
foreach($_POST as $key => $value) {
foreach ($_POST as $key => $value) {
if (in_array($key, $purify_keys)) {
if (is_array($_POST[$key])) {
$_POST[$key][$k] = sql_real_escape_string(strip_tags($_POST[$key][$k]));

View file

@ -0,0 +1,319 @@
<?php
if (!defined('_GNUBOARD_'))
exit;
// 현재 마이그레이션 버전
define('BOARD_MIGRATION_VERSION', '2.0.1');
// 표준 게시판 테이블 구조 정의
function get_standard_board_structure()
{
return [
'wr_id' => 'int(11) NOT NULL AUTO_INCREMENT',
'wr_num' => 'int(11) NOT NULL DEFAULT 0',
'wr_reply' => 'varchar(10) NOT NULL',
'wr_parent' => 'int(11) NOT NULL DEFAULT 0',
'wr_is_comment' => 'tinyint(4) NOT NULL DEFAULT 0',
'wr_comment' => 'int(11) NOT NULL DEFAULT 0',
'wr_comment_reply' => 'varchar(5) NOT NULL',
'ca_name' => 'varchar(255) NOT NULL',
'wr_option' => "set('html1','html2','secret','mail') NOT NULL",
'wr_subject' => 'varchar(255) NOT NULL',
'wr_content' => 'mediumtext NOT NULL',
'wr_extra_vars' => 'text NOT NULL',
'wr_link1' => 'text NOT NULL',
'wr_link2' => 'text NOT NULL',
'wr_link1_hit' => 'int(11) NOT NULL DEFAULT 0',
'wr_link2_hit' => 'int(11) NOT NULL DEFAULT 0',
'wr_hit' => 'int(11) NOT NULL DEFAULT 0',
'wr_good' => 'int(11) NOT NULL DEFAULT 0',
'wr_nogood' => 'int(11) NOT NULL DEFAULT 0',
'mb_id' => 'varchar(20) NOT NULL',
'wr_password' => 'varchar(255) NOT NULL',
'wr_extrapassword' => 'varchar(255) NOT NULL',
'wr_name' => 'varchar(255) NOT NULL',
'wr_email' => 'varchar(255) NOT NULL',
'wr_homepage' => 'varchar(255) NOT NULL',
'wr_datetime' => "datetime NOT NULL DEFAULT '1970-01-01 00:00:00'",
'wr_file' => 'tinyint(4) NOT NULL DEFAULT 0',
'wr_last' => 'varchar(19) NOT NULL',
'wr_ip' => 'varchar(255) NOT NULL',
'wr_facebook_user' => 'varchar(255) NOT NULL',
'wr_twitter_user' => 'varchar(255) NOT NULL',
'wr_dice1' => 'int(11) NOT NULL DEFAULT 0',
'wr_dice2' => 'int(11) NOT NULL DEFAULT 0',
'wr_log' => 'text NOT NULL',
'wr_item' => 'int(11) NOT NULL DEFAULT 0',
'wr_item_log' => "varchar(255) NOT NULL DEFAULT ''",
'wr_action' => "varchar(255) NOT NULL DEFAULT ''",
'wr_secret' => 'int(11) NOT NULL DEFAULT 0',
'wr_adult' => 'int(11) NOT NULL DEFAULT 0',
'wr_wide' => 'int(11) NOT NULL DEFAULT 0',
'wr_plip' => 'int(11) NOT NULL DEFAULT 0',
'wr_noname' => 'int(11) NOT NULL DEFAULT 0',
'wr_ing' => 'int(11) NOT NULL DEFAULT 0',
'ch_id' => 'int(11) NOT NULL DEFAULT 0',
'ch_side' => 'int(11) NOT NULL DEFAULT 0',
'ch_class' => 'int(11) NOT NULL DEFAULT 0',
'ti_id' => 'int(11) NOT NULL DEFAULT 0',
'ma_id' => 'int(11) NOT NULL DEFAULT 0',
'wr_width' => 'int(11) NOT NULL DEFAULT 0',
'wr_height' => 'int(11) NOT NULL DEFAULT 0',
'wr_url' => "varchar(255) NOT NULL DEFAULT ''",
'wr_type' => "varchar(255) NOT NULL DEFAULT ''",
'wr_1' => "varchar(255) NOT NULL DEFAULT ''",
'wr_2' => "varchar(255) NOT NULL DEFAULT ''",
'wr_3' => "varchar(255) NOT NULL DEFAULT ''",
'wr_4' => "varchar(255) NOT NULL DEFAULT ''",
'wr_5' => "varchar(255) NOT NULL DEFAULT ''",
'wr_6' => "varchar(255) NOT NULL DEFAULT ''",
'wr_7' => "varchar(255) NOT NULL DEFAULT ''",
'wr_8' => "varchar(255) NOT NULL DEFAULT ''",
'wr_9' => "varchar(255) NOT NULL DEFAULT ''",
'wr_10' => "varchar(255) NOT NULL DEFAULT ''"
];
}
// bo_version 컬럼 체크 및 추가
function check_and_add_bo_version()
{
global $g5;
$sql = "SHOW COLUMNS FROM {$g5['board_table']} LIKE 'bo_version'";
$result = sql_query($sql);
if (sql_num_rows($result) == 0) {
$sql = "ALTER TABLE {$g5['board_table']} ADD `bo_version` varchar(255) NOT NULL DEFAULT '0'";
sql_query($sql);
return true;
}
return false;
}
// 컬럼 정의 정규화 (비교를 위해)
function normalize_column_definition($definition)
{
// 소문자로 변환
$def = strtolower($definition);
// 공백 정규화
$def = preg_replace('/\s+/', ' ', $def);
$def = trim($def);
// AUTO_INCREMENT 제거 (비교 시 제외)
$def = str_replace('auto_increment', '', $def);
// int(11) -> int 형식 통일
$def = preg_replace('/int\(\d+\)/', 'int', $def);
$def = preg_replace('/tinyint\(\d+\)/', 'tinyint', $def);
// varchar/char 길이는 유지
// 따옴표 통일 (single quote)
$def = str_replace('"', "'", $def);
return trim($def);
}
// 현재 테이블 구조 가져오기 (원본 정의 포함)
function get_current_table_structure($table_name)
{
$sql = "SHOW COLUMNS FROM `{$table_name}`";
$result = sql_query($sql);
$structure = [];
while ($row = sql_fetch_array($result)) {
$type = $row['Type'];
$null = $row['Null'] == 'NO' ? 'NOT NULL' : '';
$default = '';
if ($row['Default'] !== null) {
if (in_array(strtolower($row['Default']), ['current_timestamp'])) {
$default = "DEFAULT {$row['Default']}";
} else {
$default = "DEFAULT '{$row['Default']}'";
}
} else if ($row['Null'] == 'NO' && $row['Default'] === null && $row['Extra'] != 'auto_increment') {
// NOT NULL이고 DEFAULT가 없는 경우 처리
if (strpos($type, 'int') !== false) {
$default = 'DEFAULT 0';
} else if (strpos($type, 'text') !== false) {
// text 타입은 default를 설정할 수 없음
$default = '';
} else {
$default = "DEFAULT ''";
}
}
$extra = $row['Extra'];
if ($extra == 'auto_increment') {
$extra = 'AUTO_INCREMENT';
}
$definition = trim("{$type} {$null} {$default} {$extra}");
$structure[$row['Field']] = $definition;
}
return $structure;
}
// 테이블 구조 비교 (누락 및 변경된 컬럼 모두 감지)
function compare_table_structure($table_name)
{
$standard = get_standard_board_structure();
$current = get_current_table_structure($table_name);
$missing_columns = []; // 누락된 컬럼
$modified_columns = []; // 속성이 다른 컬럼
foreach ($standard as $column => $definition) {
if (!isset($current[$column])) {
// 컬럼이 존재하지 않음
$missing_columns[$column] = $definition;
} else {
// 컬럼은 존재하지만 속성 비교
$standard_normalized = normalize_column_definition($definition);
$current_normalized = normalize_column_definition($current[$column]);
if ($standard_normalized !== $current_normalized) {
// 속성이 다름
$modified_columns[$column] = [
'current' => $current[$column],
'standard' => $definition
];
}
}
}
return [
'missing' => $missing_columns,
'modified' => $modified_columns
];
}
// 게시판 테이블 마이그레이션 실행
function migrate_board_table($bo_table)
{
global $g5;
$write_table = $g5['write_prefix'] . $bo_table;
// 테이블 존재 확인
$sql = "SHOW TABLES LIKE '{$write_table}'";
$result = sql_query($sql);
if (sql_num_rows($result) == 0) {
return ['success' => false, 'message' => '테이블이 존재하지 않습니다.'];
}
// 누락 및 변경된 컬럼 확인
$comparison = compare_table_structure($write_table);
$missing_columns = $comparison['missing'];
$modified_columns = $comparison['modified'];
if (empty($missing_columns) && empty($modified_columns)) {
// 버전 업데이트만 수행
$sql = "UPDATE {$g5['board_table']} SET bo_version = '" . BOARD_MIGRATION_VERSION . "' WHERE bo_table = '{$bo_table}'";
sql_query($sql);
return [
'success' => true,
'message' => '이미 최신 버전입니다.',
'added' => 0,
'modified' => 0
];
}
$added_count = 0;
$modified_count = 0;
$errors = [];
// 누락된 컬럼 추가
foreach ($missing_columns as $column => $definition) {
$sql = "ALTER TABLE `{$write_table}` ADD `{$column}` {$definition}";
if (sql_query($sql)) {
$added_count++;
} else {
$errors[] = "컬럼 추가 실패: {$column}";
}
}
// 변경된 컬럼 수정
foreach ($modified_columns as $column => $info) {
$sql = "ALTER TABLE `{$write_table}` MODIFY `{$column}` {$info['standard']}";
if (sql_query($sql)) {
$modified_count++;
} else {
$errors[] = "컬럼 수정 실패: {$column}";
}
}
// 버전 업데이트
$sql = "UPDATE {$g5['board_table']} SET bo_version = '" . BOARD_MIGRATION_VERSION . "' WHERE bo_table = '{$bo_table}'";
sql_query($sql);
$message = '마이그레이션이 완료되었습니다.';
if (!empty($errors)) {
$message .= ' (일부 오류: ' . implode(', ', $errors) . ')';
}
return [
'success' => true,
'message' => $message,
'added' => $added_count,
'modified' => $modified_count,
'errors' => $errors
];
}
// 모든 게시판 체크
function check_all_boards_migration()
{
global $g5;
check_and_add_bo_version();
$sql = "SELECT bo_table, bo_version FROM {$g5['board_table']}";
$result = sql_query($sql);
$boards_need_update = [];
while ($row = sql_fetch_array($result)) {
if ($row['bo_version'] != BOARD_MIGRATION_VERSION) {
$write_table = $g5['write_prefix'] . $row['bo_table'];
$comparison = compare_table_structure($write_table);
$boards_need_update[] = [
'bo_table' => $row['bo_table'],
'current_version' => $row['bo_version'],
'missing_columns' => count($comparison['missing']),
'modified_columns' => count($comparison['modified'])
];
}
}
return $boards_need_update;
}
// 특정 게시판의 상세 차이점 확인
function get_board_migration_details($bo_table)
{
global $g5;
$write_table = $g5['write_prefix'] . $bo_table;
// 테이블 존재 확인
$sql = "SHOW TABLES LIKE '{$write_table}'";
$result = sql_query($sql);
if (sql_num_rows($result) == 0) {
return ['success' => false, 'message' => '테이블이 존재하지 않습니다.'];
}
$comparison = compare_table_structure($write_table);
return [
'success' => true,
'bo_table' => $bo_table,
'missing_columns' => $comparison['missing'],
'modified_columns' => $comparison['modified']
];
}

View file

@ -0,0 +1,48 @@
<?php
include_once "./_common.php";
header('Content-Type: application/json');
$source_board = isset($_POST['source_board']) ? preg_replace('/[^a-z0-9_]/i', '', $_POST['source_board']) : '';
$target_board = isset($_POST['target_board']) ? preg_replace('/[^a-z0-9_]/i', '', $_POST['target_board']) : '';
if (!$source_board || !$target_board) {
echo json_encode(['warning' => false, 'message' => '']);
exit;
}
$source_table = $g5['write_prefix'] . $source_board;
$target_table = $g5['write_prefix'] . $target_board;
$source_exists = sql_query("SHOW TABLES LIKE '{$source_table}'", false);
$target_exists = sql_query("SHOW TABLES LIKE '{$target_table}'", false);
if (!sql_num_rows($source_exists) || !sql_num_rows($target_exists)) {
echo json_encode(['warning' => true, 'message' => '게시판 테이블이 존재하지 않습니다.']);
exit;
}
$source_columns = [];
$result = sql_query("SHOW COLUMNS FROM {$source_table}");
while ($row = sql_fetch_array($result)) {
$source_columns[] = $row['Field'];
}
$target_columns = [];
$result = sql_query("SHOW COLUMNS FROM {$target_table}");
while ($row = sql_fetch_array($result)) {
$target_columns[] = $row['Field'];
}
$missing_columns = array_diff($source_columns, $target_columns);
$exclude_columns = ['wr_id', 'wr_num', 'wr_reply', 'wr_parent'];
$missing_columns = array_diff($missing_columns, $exclude_columns);
if (count($missing_columns) > 0) {
$message = '대상 게시판에 존재하지 않는 필드가 있어 해당 데이터는 복사되지 않습니다: ' . implode(', ', $missing_columns);
echo json_encode(['warning' => true, 'message' => $message]);
} else {
echo json_encode(['warning' => false, 'message' => '']);
}
?>

View file

@ -0,0 +1,295 @@
<?php
include_once "./_common.php";
auth_check($auth[$sub_menu], 'r');
$bo_table = isset($_GET['bo_table']) ? preg_replace('/[^a-z0-9_]/i', '', $_GET['bo_table']) : '';
if (!$bo_table) {
alert('게시판을 선택해주세요.');
}
$board = sql_fetch(" SELECT * FROM {$g5['board_table']} WHERE bo_table = '{$bo_table}' ");
if (!$board) {
alert('존재하지 않는 게시판입니다.');
}
$write_table = $g5['write_prefix'] . $bo_table;
$sfl = isset($_GET['sfl']) ? clean_xss_tags($_GET['sfl']) : '';
$stx = isset($_GET['stx']) ? clean_xss_tags($_GET['stx']) : '';
$sst = isset($_GET['sst']) ? preg_replace('/[^a-z0-9_]/i', '', $_GET['sst']) : 'wr_num';
$sod = isset($_GET['sod']) && in_array($_GET['sod'], ['asc', 'desc']) ? $_GET['sod'] : 'desc';
$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
$sql_common = " FROM {$write_table} ";
$sql_search = " WHERE (1) ";
if ($stx) {
$sql_search .= " AND ( ";
switch ($sfl) {
case "wr_subject":
case "wr_content":
$sql_search .= " ({$sfl} LIKE '%{$stx}%') ";
break;
case "wr_name":
$sql_search .= " (wr_name LIKE '%{$stx}%') ";
break;
default:
$sql_search .= " (wr_subject LIKE '%{$stx}%' OR wr_content LIKE '%{$stx}%') ";
break;
}
$sql_search .= " ) ";
}
$sql_order = " ORDER BY {$sst} {$sod} ";
$sql = " SELECT COUNT(*) AS cnt {$sql_common} {$sql_search} ";
$row = sql_fetch($sql);
$total_count = $row['cnt'];
$rows = $config['cf_page_rows'];
$total_page = ceil($total_count / $rows);
if ($page < 1)
$page = 1;
$from_record = ($page - 1) * $rows;
$sql = " SELECT * {$sql_common} {$sql_search} {$sql_order} LIMIT {$from_record}, {$rows} ";
$result = sql_query($sql);
$board_list = [];
$board_sql = " SELECT bo_table, bo_subject FROM {$g5['board_table']} WHERE bo_table != '{$bo_table}' ORDER BY gr_id, bo_table ";
$board_result = sql_query($board_sql);
while ($row = sql_fetch_array($board_result)) {
$board_list[] = $row;
}
$qstr = 'bo_table=' . $bo_table;
if ($sfl)
$qstr .= '&sfl=' . $sfl;
if ($stx)
$qstr .= '&stx=' . urlencode($stx);
if ($sst)
$qstr .= '&sst=' . $sst;
if ($sod)
$qstr .= '&sod=' . $sod;
if ($page)
$qstr .= '&page=' . $page;
$listall = '<a href="' . $_SERVER['SCRIPT_NAME'] . '?bo_table=' . $bo_table . '" class="ov_listall">처음</a>';
$g5['title'] = '게시물 이동/복사';
include_once "./admin.head.php";
$colspan = 8;
?>
<div class="local_ov01 local_ov">
<?php echo $listall ?>
<strong><?php echo get_text($board['bo_subject']) ?> (<?php echo $bo_table ?>)</strong>
전체게시물 <?php echo number_format($total_count) ?>
</div>
<form name="fsearch" id="fsearch" class="local_sch01 local_sch" method="get">
<input type="hidden" name="bo_table" value="<?php echo $bo_table ?>">
<label for="sfl" class="sound_only">검색대상</label>
<select name="sfl" id="sfl">
<option value="wr_subject" <?php echo get_selected($sfl, "wr_subject"); ?>>제목</option>
<option value="wr_content" <?php echo get_selected($sfl, "wr_content"); ?>>내용</option>
<option value="wr_name" <?php echo get_selected($sfl, "wr_name"); ?>>작성자</option>
<option value="wr_subject||wr_content" <?php echo get_selected($sfl, "wr_subject||wr_content"); ?>>제목+내용</option>
</select>
<label for="stx" class="sound_only">검색어</label>
<input type="text" name="stx" value="<?php echo $stx ?>" id="stx" class="frm_input">
<input type="submit" value="검색" class="btn_submit">
</form>
<br />
<form name="fwritelist" id="fwritelist" action="./board_move_update.php" onsubmit="return fwritelist_submit(this);"
method="post">
<input type="hidden" name="bo_table" value="<?php echo $bo_table ?>">
<input type="hidden" name="sst" value="<?php echo $sst ?>">
<input type="hidden" name="sod" value="<?php echo $sod ?>">
<input type="hidden" name="sfl" value="<?php echo $sfl ?>">
<input type="hidden" name="stx" value="<?php echo $stx ?>">
<input type="hidden" name="page" value="<?php echo $page ?>">
<input type="hidden" name="act_button" value="">
<input type="hidden" name="target_board" id="target_board_hidden" value="">
<div class="tbl_head01 tbl_wrap">
<div class="btn_left">
<label for="target_board_select">대상 게시판 선택:</label>
<select name="target_board_select" id="target_board_select" class="frm_input">
<option value="">선택하세요</option>
<?php foreach ($board_list as $b) { ?>
<option value="<?php echo $b['bo_table'] ?>"><?php echo get_text($b['bo_subject']) ?>
(<?php echo $b['bo_table'] ?>)</option>
<?php } ?>
</select>
<span id="warning_msg" style="color:#ff0000;margin-left:10px;display:none;"></span>
</div>
<table>
<caption><?php echo $g5['title']; ?> 목록</caption>
<colgroup>
<col style="width:45px;">
<col style="width:80px;">
<col>
<col style="width:120px;">
<col style="width:80px;">
<col style="width:80px;">
<col style="width:120px;">
</colgroup>
<thead>
<tr>
<th scope="col">
<label for="chkall" class="sound_only">전체선택</label>
<input type="checkbox" name="chkall" value="1" id="chkall" onclick="check_all(this.form)">
</th>
<th scope="col">번호</th>
<th scope="col">제목</th>
<th scope="col">작성자</th>
<th scope="col">조회</th>
<th scope="col">댓글</th>
<th scope="col">작성일</th>
</tr>
</thead>
<tbody>
<?php
$list = [];
for ($i = 0; $row = sql_fetch_array($result); $i++) {
$list[$i] = get_list($row, $board, $board['bo_subject'], $board['bo_mobile_subject']);
$bg = 'bg' . ($i % 2);
?>
<tr class="<?php echo $bg; ?>">
<td class="td_chk">
<input type="checkbox" name="chk[]" value="<?php echo $list[$i]['wr_id'] ?>" id="chk_<?php echo $i ?>">
</td>
<td class="td_num"><?php echo $list[$i]['wr_id'] ?></td>
<td class="td_subject">
<?php echo $list[$i]['reply'] ?>
<a href="<?php echo G5_BBS_URL ?>/board.php?bo_table=<?php echo $bo_table ?>&wr_id=<?php echo $list[$i]['wr_id'] ?>"
target="_blank">
<?php echo $list[$i]['subject'] ?>
<?php if ($list[$i]['icon_file'])
echo ' ' . $list[$i]['icon_file']; ?>
<?php if ($list[$i]['icon_new'])
echo ' ' . $list[$i]['icon_new']; ?>
</a>
</td>
<td class="td_name"><?php echo $list[$i]['name'] ?></td>
<td class="td_num"><?php echo $list[$i]['wr_hit'] ?></td>
<td class="td_num"><?php echo $list[$i]['wr_comment'] ?></td>
<td class="td_date"><?php echo $list[$i]['datetime2'] ?></td>
</tr>
<?php
}
if ($i == 0) {
echo '<tr><td colspan="' . $colspan . '" class="empty_table">자료가 없습니다.</td></tr>';
}
?>
</tbody>
</table>
</div>
<div class="btn_confirm">
<div class="btn ty3">
<span class="material-icons">drive_file_move</span>
<input type="submit" name="act_btn" value="선택이동" title="선택이동" onclick="document.pressed='move'">
</div>
<div class="btn ty3">
<span class="material-icons">content_copy</span>
<input type="submit" name="act_btn" value="선택복사" title="선택복사" onclick="document.pressed='copy'">
</div>
</div>
</form>
<br />
<?php
$pagelist = get_paging(G5_IS_MOBILE ? $config['cf_mobile_pages'] : $config['cf_write_pages'], $page, $total_page, $_SERVER['SCRIPT_NAME'] . '?' . $qstr . '&page=');
echo $pagelist;
?>
<div class="local_desc01 local_desc">
<p>
<strong>이동:</strong> 선택한 게시물을 대상 게시판으로 이동합니다. 원본 게시물은 삭제됩니다.<br>
<strong>복사:</strong> 선택한 게시물을 대상 게시판에 복사합니다. 원본 게시물은 유지됩니다.<br>
게시판 테이블 구조가 다른 경우, 존재하는 필드만 복사되며 경고 메시지가 표시됩니다.
</p>
</div>
<script>
var warningShown = false;
function fwritelist_submit(f) {
var targetBoard = document.getElementById('target_board_select').value;
if (!is_checked("chk[]")) {
alert(document.pressed === 'move' ? '이동' : '복사' + "할 게시물을 하나 이상 선택하세요.");
return false;
}
if (!targetBoard) {
alert('대상 게시판을 선택하세요.');
document.getElementById('target_board_select').focus();
return false;
}
f.target_board.value = targetBoard;
f.act_button.value = document.pressed;
var actionText = (document.pressed === 'move') ? '이동' : '복사';
var confirmMsg = '선택한 게시물을 ' + actionText + '하시겠습니까?';
if (document.pressed === 'move') {
confirmMsg += '\n\n원본 게시물은 삭제됩니다.';
}
if (warningShown) {
confirmMsg += '\n\n경고: 일부 필드가 복사되지 않을 수 있습니다.';
}
if (!confirm(confirmMsg)) {
return false;
}
return true;
}
document.getElementById('target_board_select').addEventListener('change', function () {
var targetBoard = this.value;
var sourceBoard = '<?php echo $bo_table ?>';
warningShown = false;
document.getElementById('warning_msg').style.display = 'none';
document.getElementById('warning_msg').innerHTML = '';
if (!targetBoard) {
return;
}
var xhr = new XMLHttpRequest();
xhr.open('POST', './board_move_check.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function () {
if (xhr.status === 200) {
try {
var response = JSON.parse(xhr.responseText);
if (response.warning) {
warningShown = true;
document.getElementById('warning_msg').innerHTML = '⚠ ' + response.message;
document.getElementById('warning_msg').style.display = 'inline';
}
} catch (e) {
console.error('Error parsing response:', e);
}
}
};
xhr.send('source_board=' + sourceBoard + '&target_board=' + targetBoard);
});
</script>
<?php
include_once "./admin.tail.php";
?>

View file

@ -0,0 +1,286 @@
<?php
include_once "./_common.php";
auth_check($auth[$sub_menu], 'w');
$bo_table = isset($_POST['bo_table']) ? preg_replace('/[^a-z0-9_]/i', '', $_POST['bo_table']) : '';
$target_board = isset($_POST['target_board']) ? preg_replace('/[^a-z0-9_]/i', '', $_POST['target_board']) : '';
$act_button = isset($_POST['act_button']) ? $_POST['act_button'] : '';
$chk = isset($_POST['chk']) ? $_POST['chk'] : [];
if (!in_array($act_button, ['move', 'copy'])) {
alert('잘못된 요청입니다.');
}
if (!$bo_table || !$target_board || !$act_button || empty($chk)) {
alert('필수 항목이 누락되었습니다.');
}
if ($bo_table === $target_board) {
alert('같은 게시판으로는 이동/복사할 수 없습니다.');
}
$source_board = sql_fetch("SELECT * FROM {$g5['board_table']} WHERE bo_table = '{$bo_table}'");
$dest_board = sql_fetch("SELECT * FROM {$g5['board_table']} WHERE bo_table = '{$target_board}'");
if (!$source_board || !$dest_board) {
alert('존재하지 않는 게시판입니다.');
}
$source_table = $g5['write_prefix'] . $bo_table;
$target_table = $g5['write_prefix'] . $target_board;
$source_columns = [];
$result = sql_query("SHOW COLUMNS FROM {$source_table}");
while ($row = sql_fetch_array($result)) {
$source_columns[$row['Field']] = $row;
}
$target_columns = [];
$result = sql_query("SHOW COLUMNS FROM {$target_table}");
while ($row = sql_fetch_array($result)) {
$target_columns[$row['Field']] = $row;
}
$exclude_fields = ['wr_id', 'wr_num'];
$common_columns = [];
foreach ($source_columns as $col_name => $col_info) {
if (isset($target_columns[$col_name]) && !in_array($col_name, $exclude_fields)) {
$common_columns[] = $col_name;
}
}
if (empty($common_columns)) {
alert('복사할 수 있는 공통 컬럼이 없습니다.');
}
$success_count = 0;
$fail_count = 0;
$error_messages = [];
foreach ($chk as $wr_id) {
$wr_id = (int) $wr_id;
$write = sql_fetch("SELECT * FROM {$source_table} WHERE wr_id = '{$wr_id}'");
if (!$write) {
$fail_count++;
$error_messages[] = "게시물 ID {$wr_id}를 찾을 수 없습니다.";
continue;
}
$is_reply = $write['wr_reply'] ? true : false;
if ($is_reply && $act_button === 'move') {
$parent_id = $write['wr_parent'];
$parent_check = sql_fetch("SELECT wr_id FROM {$source_table} WHERE wr_id = '{$parent_id}'");
if (!$parent_check) {
$write['wr_reply'] = '';
$write['wr_parent'] = 0;
}
}
try {
$insert_values = [];
$insert_fields = [];
foreach ($common_columns as $col) {
if ($col === 'wr_num')
continue;
if ($col === 'wr_reply' || $col === 'wr_parent') {
if ($col === 'wr_reply') {
$insert_fields[] = $col;
$insert_values[] = "''";
} else if ($col === 'wr_parent') {
$insert_fields[] = $col;
$insert_values[] = "0";
}
continue;
}
$insert_fields[] = $col;
$value = $write[$col];
if ($col === 'bo_table') {
$insert_values[] = "'{$target_board}'";
} else {
$insert_values[] = "'" . sql_real_escape_string($value) . "'";
}
}
$row = sql_fetch("SELECT MIN(wr_num) AS min_wr_num FROM {$target_table}");
$wr_num = $row['min_wr_num'] - 1;
$insert_fields[] = 'wr_num';
$insert_values[] = "'{$wr_num}'";
$sql = "INSERT INTO {$target_table} (" . implode(', ', $insert_fields) . ")
VALUES (" . implode(', ', $insert_values) . ")";
sql_query($sql);
$new_wr_id = sql_insert_id();
if (isset($write['wr_is_comment']) && $write['wr_is_comment'] == 0) {
sql_query("UPDATE {$target_table} SET wr_parent = '{$new_wr_id}' WHERE wr_id = '{$new_wr_id}'");
}
if ($write['wr_file']) {
copy_board_files($bo_table, $wr_id, $target_board, $new_wr_id, $write);
}
if ($act_button === 'move') {
sql_query("DELETE FROM {$g5['board_new_table']} WHERE bo_table = '{$bo_table}' AND wr_id = '{$wr_id}'");
sql_query("DELETE FROM {$g5['board_good_table']} WHERE bo_table = '{$bo_table}' AND wr_id = '{$wr_id}'");
sql_query("DELETE FROM {$source_table} WHERE wr_id = '{$wr_id}'");
move_board_files($bo_table, $wr_id, $target_board, $new_wr_id);
}
sql_query("UPDATE {$g5['board_table']} SET bo_count_write = bo_count_write + 1 WHERE bo_table = '{$target_board}'");
if ($act_button === 'move') {
sql_query("UPDATE {$g5['board_table']} SET bo_count_write = bo_count_write - 1 WHERE bo_table = '{$bo_table}'");
}
$success_count++;
} catch (Exception $e) {
$fail_count++;
$error_messages[] = "게시물 ID {$wr_id} 처리 중 오류: " . $e->getMessage();
}
}
$action_text = ($act_button === 'move') ? '이동' : '복사';
$message = "{$success_count}개의 게시물이 {$action_text}되었습니다.";
if ($fail_count > 0) {
$message .= "\\n{$fail_count}개의 게시물 처리 중 오류가 발생했습니다.";
if (!empty($error_messages)) {
$message .= "\\n\\n상세 오류:\\n" . implode("\\n", array_slice($error_messages, 0, 5));
if (count($error_messages) > 5) {
$message .= "\\n... 외 " . (count($error_messages) - 5) . "";
}
}
}
$qstr = 'bo_table=' . $bo_table;
if (isset($_POST['sod']))
$qstr .= '&sod=' . $_POST['sod'];
if (isset($_POST['sfl']))
$qstr .= '&sfl=' . $_POST['sfl'];
if (isset($_POST['stx']))
$qstr .= '&stx=' . urlencode($_POST['stx']);
if (isset($_POST['page']))
$qstr .= '&page=' . $_POST['page'];
goto_url('./board_move_list.php?' . $qstr, false, $message);
function copy_board_files($source_bo_table, $source_wr_id, $target_bo_table, $target_wr_id, $write_data)
{
global $g5;
$source_dir = G5_DATA_PATH . '/file/' . $source_bo_table;
$target_dir = G5_DATA_PATH . '/file/' . $target_bo_table;
if (!is_dir($target_dir)) {
@mkdir($target_dir, G5_DIR_PERMISSION);
@chmod($target_dir, G5_DIR_PERMISSION);
}
for ($i = 0; $i < 10; $i++) {
$file_field = 'wr_file' . $i;
$source_field = 'bf_source' . $i;
if (isset($write_data[$file_field]) && $write_data[$file_field]) {
$source_file = $source_dir . '/' . $write_data[$file_field];
if (file_exists($source_file)) {
$new_filename = $target_wr_id . '_' . $i . '_' . time() . substr($write_data[$file_field], strrpos($write_data[$file_field], '.'));
$target_file = $target_dir . '/' . $new_filename;
if (@copy($source_file, $target_file)) {
@chmod($target_file, G5_FILE_PERMISSION);
$bf_source = isset($write_data[$source_field]) ? $write_data[$source_field] : basename($write_data[$file_field]);
$bf_filesize = filesize($target_file);
$bf_width = 0;
$bf_height = 0;
$bf_type = 0;
if (preg_match("/\.(gif|jpg|jpeg|png)$/i", $new_filename)) {
$size = @getimagesize($target_file);
if ($size) {
$bf_width = $size[0];
$bf_height = $size[1];
$bf_type = $size[2];
}
}
$sql = " INSERT INTO {$g5['board_file_table']}
SET bo_table = '{$target_bo_table}',
wr_id = '{$target_wr_id}',
bf_no = '{$i}',
bf_source = '" . sql_real_escape_string($bf_source) . "',
bf_file = '{$new_filename}',
bf_download = 0,
bf_content = '',
bf_filesize = '{$bf_filesize}',
bf_width = '{$bf_width}',
bf_height = '{$bf_height}',
bf_type = '{$bf_type}',
bf_datetime = '" . G5_TIME_YMDHIS . "' ";
sql_query($sql);
}
}
}
}
}
function move_board_files($source_bo_table, $source_wr_id, $target_bo_table, $target_wr_id)
{
global $g5;
$sql = "SELECT * FROM {$g5['board_file_table']}
WHERE bo_table = '{$source_bo_table}' AND wr_id = '{$source_wr_id}'
ORDER BY bf_no";
$result = sql_query($sql);
$source_dir = G5_DATA_PATH . '/file/' . $source_bo_table;
$target_dir = G5_DATA_PATH . '/file/' . $target_bo_table;
if (!is_dir($target_dir)) {
@mkdir($target_dir, G5_DIR_PERMISSION);
@chmod($target_dir, G5_DIR_PERMISSION);
}
while ($row = sql_fetch_array($result)) {
$source_file = $source_dir . '/' . $row['bf_file'];
if (file_exists($source_file)) {
$new_filename = $target_wr_id . '_' . $row['bf_no'] . '_' . time() . substr($row['bf_file'], strrpos($row['bf_file'], '.'));
$target_file = $target_dir . '/' . $new_filename;
if (@rename($source_file, $target_file)) {
$sql = " INSERT INTO {$g5['board_file_table']}
SET bo_table = '{$target_bo_table}',
wr_id = '{$target_wr_id}',
bf_no = '{$row['bf_no']}',
bf_source = '" . sql_real_escape_string($row['bf_source']) . "',
bf_file = '{$new_filename}',
bf_download = '{$row['bf_download']}',
bf_content = '" . sql_real_escape_string($row['bf_content']) . "',
bf_filesize = '{$row['bf_filesize']}',
bf_width = '{$row['bf_width']}',
bf_height = '{$row['bf_height']}',
bf_type = '{$row['bf_type']}',
bf_datetime = '{$row['bf_datetime']}' ";
sql_query($sql);
}
}
}
sql_query("DELETE FROM {$g5['board_file_table']} WHERE bo_table = '{$source_bo_table}' AND wr_id = '{$source_wr_id}'");
}
?>

View file

@ -69,7 +69,7 @@ if (!$config["cf_community"] || !$is_community_init) {
</table>
<?php if (!$is_community_init) {?>
<div class="list_confirm">
<a href="./_create_community_db.php">DB TABLE 생성</a>
<a href="./migrate/_create_community_db.php">DB TABLE 생성</a>
</div>
<?php } ?>
<?php if (!$config["cf_community"]) {?>
@ -87,38 +87,13 @@ if (!$config["cf_community"] || !$is_community_init) {
<p>커뮤니티용 기능에 필요한 설정입니다.</p>
</div>
<div class="tbl_frm01 tbl_wrap">
<table>
<caption>홈페이지 기본환경 설정</caption>
<colgroup>
<col style="width: 150px;">
<col>
</colgroup>
<tbody>
<tr>
<th scope="row">공개설정</th>
<td>
<input type="checkbox" name="cf_2" value="1" id="cf_2" <?php echo $config['cf_2'] ? 'checked' : ''; ?>>
<label for="cf_2">캐릭터생성 가능</label>
&nbsp;&nbsp;
<input type="checkbox" name="cf_3" value="1" id="cf_3" <?php echo $config['cf_3'] ? 'checked' : ''; ?>>
<label for="cf_3">캐릭터수정 가능</label>
</td>
</tr>
<tr>
<th scope="row">기능설정</th>
<td>
<input type="checkbox" name="cf_4" value="1" id="cf_4" <?php echo $config['cf_4'] ? 'checked' : ''; ?>>
<label for="cf_4">탐색사용</label>
&nbsp;&nbsp;
<input type="checkbox" name="cf_5" value="1" id="cf_5" <?php echo $config['cf_5'] ? 'checked' : ''; ?>>
<label for="cf_5">조합(레시피)사용</label>
&nbsp;&nbsp;
<input type="checkbox" name="cf_6" value="1" id="cf_6" <?php echo $config['cf_6'] ? 'checked' : ''; ?>>
<label for="cf_6">탐색 수행 가능</label>
</td>
</tr>
</tbody>
</table>
<?php
setCheckbox("캐릭터 생성 허용", "값을 설정하는 경우 회원은 새 캐릭터를 작성할 수 있습니다.", "cf_2", "1", $config);
setCheckbox("캐릭터 수정 허용", "값을 설정하는 경우 회원은 캐릭터를 수정할 수 있습니다.", "cf_3", "1", $config);
setCheckbox("탐색 기능 사용", "탐색 기능을 사용할 지 설정합니다.<br>관련된 플러그인, 애드온, 모듈과 그것을 지원하는 스킨이 설치되어 있어야 합니다.", "cf_4", "1", $config);
setCheckbox("조합 기능 사용", "조합 기능을 사용할 지 설정합니다.<br>관련된 플러그인, 애드온, 모듈과 그것을 지원하는 스킨이 설치되어 있어야 합니다.", "cf_5", "1", $config);
setCheckbox("탐색 수행 가능 여부 설정", "탐색을 수행할 수 있는지 여부를 설정합니다.<br>관련된 플러그인, 애드온, 모듈과 그것을 지원하는 스킨이 설치되어 있어야 합니다.", "cf_6", "1", $config);
?>
</div>
</section>
<?php echo $frm_submit; ?>
@ -126,36 +101,11 @@ if (!$config["cf_community"] || !$is_community_init) {
<h2 class="h2_frm">기능 설정</h2>
<?php echo $pg_anchor ?>
<div class="tbl_frm01 tbl_wrap">
<table>
<colgroup>
<col style="width: 150px;">
<col>
</colgroup>
<tbody>
<tr>
<th scope="row">캐릭터 최대 생성 갯수</th>
<td>
<input type="text" name="cf_character_count" value="<?php echo get_text($config['cf_character_count']) ?>"
id="cf_character_count" size="10">
</td>
</tr>
<tr>
<th scope="row">최초 스탯 포인트</th>
<td>
<?php echo help('스탯 사용 설정 시, 캐릭터가 최초로 획득하는 스탯 포인트를 설정합니다.') ?>
<input type="text" name="cf_status_point" value="<?php echo get_text($config['cf_status_point']) ?>"
id="cf_status_point" size="10">
</td>
</tr>
<tr>
<th scope="row">하루 탐색 횟수</th>
<td>
<input type="text" name="cf_search_count" value="<?php echo get_text($config['cf_search_count']) ?>"
id="cf_search_count" size="10">
</td>
</tr>
</tbody>
</table>
<?php
setNumberInput("캐릭터 최대 보유 수", "회원이 보유할 수 있는 캐릭터의 허용 인원을 설정합니다.", "cf_character_count", $config, "", "", 0);
setNumberInput("초기 스탯 포인트", "스탯 사용 설정 시 초기에 캐릭터가 보유할 포인트 양을 설정합니다.", "cf_status_point", $config, "", $config['cf_money_pice'], 0);
setNumberInput("일일 탐색 횟수 제한", "탐색 기능을 사용하는 경우 하루에 얼마나 탐색을 진행할 수 있는지 설정합니다.<br>관련된 플러그인, 애드온, 모듈과 그것을 지원하는 스킨이 설치되어 있어야 합니다.", "cf_search_count", $config, "", "", 0);
?>
</div>
</section>
<?php echo $frm_submit; ?>
@ -163,89 +113,17 @@ if (!$config["cf_community"] || !$is_community_init) {
<h2 class="h2_frm">기타 항목명 설정</h2>
<?php echo $pg_anchor ?>
<div class="tbl_frm01 tbl_wrap">
<table>
<colgroup>
<col style="width: 150px;">
<col style="width: 100px;">
<col>
</colgroup>
<tbody>
<tr>
<th scope="row" rowspan="2"><?= $config['cf_money'] ? $config['cf_money'] : "(포인트)" ?> 설정</th>
<td>명칭</td>
<td>
<input type="text" name="cf_money" value="<?php echo get_text($config['cf_money']) ?>" id="cf_money"
size="30">
</td>
</tr>
<tr>
<td>단위</td>
<td>
<input type="text" name="cf_money_pice" value="<?php echo get_text($config['cf_money_pice']) ?>"
id="cf_money_pice" size="30">
</td>
</tr>
<tr>
<th scope="row" rowspan="2"><?= $config['cf_exp_name'] ? $config['cf_exp_name'] : "(경험치)" ?> 설정</th>
<td>명칭</td>
<td>
<input type="text" name="cf_exp_name" value="<?php echo get_text($config['cf_exp_name']) ?>"
id="cf_exp_name" size="30">
</td>
</tr>
<tr>
<td>단위</td>
<td>
<input type="text" name="cf_exp_pice" value="<?php echo get_text($config['cf_exp_pice']) ?>"
id="cf_exp_pice" size="30">
</td>
</tr>
<tr>
<th scope="row"><?= $config['cf_rank_name'] ? $config['cf_rank_name'] : "(랭크)" ?> 설정</th>
<td>명칭</td>
<td>
<input type="text" name="cf_rank_name" value="<?php echo get_text($config['cf_rank_name']) ?>"
id="cf_rank_name" size="30">
</td>
</tr>
<tr>
<th scope="row"><?= $config['cf_side_title'] ? $config['cf_side_title'] : "(소속)" ?> (선택A)설정</th>
<td>명칭</td>
<td>
<?php echo help('명칭이 입력되지 않을 시, 프로필에 출력되지 않습니다.') ?>
<input type="text" name="cf_side_title" value="<?php echo get_text($config['cf_side_title']) ?>"
id="cf_side_title" size="30">
</td>
</tr>
<tr>
<th scope="row"><?= $config['cf_class_title'] ? $config['cf_class_title'] : "(클래스)" ?> (선택B)설정</th>
<td>명칭</td>
<td>
<?php echo help('명칭이 입력되지 않을 시, 프로필에 출력되지 않습니다.') ?>
<input type="text" name="cf_class_title" value="<?php echo get_text($config['cf_class_title']) ?>"
id="cf_class_title" size="30">
</td>
</tr>
<tr>
<th scope="row">상점 카테고리</th>
<td>-</td>
<td>
<?php echo help('카테고리 구분은 || 를 사용합니다.') ?>
<input type="text" name="cf_shop_category" value="<?php echo get_text($config['cf_shop_category']) ?>"
id="cf_shop_category" size="100" placeholder="예시) 일반||이벤트">
</td>
</tr>
<tr>
<th scope="row">아이템 기능</th>
<td>-</td>
<td>
<?php echo help('기능 구분은 || 를 사용합니다.') ?>
<input type="text" name="cf_item_category" value="<?php echo get_text($config['cf_item_category']) ?>"
id="cf_item_category" size="100" placeholder="예시) 일반||프로필수정||아이템추가||스탯회복">
</td>
</tr>
</tbody>
</table>
<?php
setTextInput("포인트 명칭", "포인트의 이름을 설정합니다.", "cf_money", $config);
setTextInput("포인트 단위", "포인트의 단위를 설정합니다.", "cf_money_pice", $config);
setTextInput("경험치 명칭", "경험치의 이름을 설정합니다.", "cf_exp_name", $config);
setTextInput("경험치 단위", "경험치의 단위를 설정합니다.", "cf_exp_pice", $config);
setTextInput("랭크 명칭", "랭크의 이름을 설정합니다.", "cf_rank_name", $config);
setTextInput("소속 명칭", "소속의 이름을 설정합니다.<br>설정하지 않는 경우 사용하지 않는 것으로 간주됩니다.", "cf_side_title", $config);
setTextInput("클래스 명칭", "클래스의 이름을 설정합니다.<br>설정하지 않는 경우 사용하지 않는 것으로 간주됩니다.", "cf_class_title", $config);
setListEditInput("상점 카테고리", "상점 아이템의 카테고리를 설정합니다.", "cf_shop_category", $config, "||");
setListEditInput("아이템 기능", "아이템 기능을 설정합니다.<br>기능에 할당된 아이템이 있는 상태에서 삭제할 경우 정상 동작을 보장할 수 없습니다.", "cf_item_category", $config, "||");
?>
</div>
</section>
<?php echo $frm_submit; ?>

View file

@ -33,4 +33,4 @@ EventHandler::triggerEvent("amber.admin.community_form_update");
sql_query($sql);
goto_url('./community_form.php');
goto_url(G5_ADMIN_URL . '/community_form.php');

View file

@ -3,7 +3,7 @@ th a {
display: inline-block;
vertical-align: middle;
padding: 3px 10px;
background: var(--theme-color-a);
background: var(--theme-sub-500);
color: #fff;
margin: 5px 0 0;
}
@ -12,33 +12,30 @@ th a+a {
margin-top: 3px;
}
#wrap {
html>body #container {
padding: 0;
}
.addon_conf_form {
height: 100%;
}
#container {
padding: 0 !important;
min-height: 100%;
}
#wrapper {
height: 100%;
box-sizing: border-box;
}
#container section.addon_config {
#container .addon_config {
display: flex;
height: 100%;
padding: 8px;
height: auto;
gap: 8px;
box-sizing: border-box;
margin-bottom: 0;
padding: 0;
width: calc(100% - 8px);
height: 100%
}
.addon_config>nav {
min-width: 200px;
display: flex;
flex-direction: column;
border: 1px solid var(--theme-color-d);
border-radius: 4px;
background: var(--theme-gray-800);
overflow:hidden;
}
@ -48,12 +45,13 @@ th a+a {
}
.addon_config>nav>a.selected {
background: var(--theme-color-a);
background: var(--theme-sub-300);
color: var(--black);
font-weight: bold;
}
.addon_config>nav>span {
background: var(--theme-color-d);
background: var(--theme-gray-500);
color: #FFF;
line-height: 48px;
font-size: 14px;
@ -71,10 +69,6 @@ td a {
color: var(--theme-color-d);
}
.footer-copyright {
padding: 20px !important;
}
span.empty {
display: flex;
flex-direction: column;

View file

@ -0,0 +1,257 @@
@charset "utf-8";
.adm-form {
padding: 16px;
border-bottom: 1px solid var(--theme-color-e, #efeff5);
}
.adm-form input,
.adm-form textarea,
.adm-form select {
outline-color: var(--theme-color-e);
}
.adm-form:hover {
background: var(--theme-color-0);
}
.adm-form:last-child {
margin-bottom: 8px;
}
.adm-form-postfix {
min-width: 40px;
text-align: center;
}
.adm-form-colflex {
display: flex;
gap: 8px;
}
.adm-form-rowflex {
display: flex;
gap: 8px;
flex-direction: column;
justify-content: center;
}
.adm-form-colflex .adm-form-flex-full {
flex-grow: 1;
}
.adm-form-name {
font-size: 16px;
font-weight: bold;
}
.adm-form-desc {
margin: 8px 0 0 0;
font-size: 14px;
}
.adm-form-check {
position: relative;
width: 48px;
height: 24px;
margin: 4px 0;
}
.adm-form-check input[type=checkbox] {
width: 48px;
height: 24px;
position: relative;
cursor: pointer;
opacity: 0;
}
.adm-form-check input[type=checkbox]+.adm-form-checkbox-cover {
pointer-events: none;
box-shadow: inset 0 0 3px #0004;
background: #DDD;
width: 48px;
height: 24px;
border-radius: 24px;
position: absolute;
left: 0;
top: 0;
display: flex;
justify-content: center;
transition: .25s;
}
.adm-form-check input[type=checkbox]+.adm-form-checkbox-cover::before {
content: "";
height: 18px;
width: 18px;
border-radius: 50%;
background: #FFF;
box-shadow: 0 0 3px #0004;
transform: translateX(-12px) translateY(3px);
box-sizing: border-box;
transition: .25s;
}
.adm-form-check input[type=checkbox]:checked+.adm-form-checkbox-cover {
background: var(--theme-color-e, #06C);
}
.adm-form-check input[type=checkbox]:checked+.adm-form-checkbox-cover::before {
transform: translateX(12px) translateY(3px);
}
.adm-form-select {
padding: 4px;
}
.adm-form-select select {
width: 100%;
box-sizing: border-box;
cursor: pointer;
border: 1px solid var(--theme-color-e, #efeff5);
border-radius: 4px;
padding: 8px;
height: auto
}
.adm-form-text {
padding: 4px;
}
.adm-form-text input[type=text] {
border: 1px solid var(--theme-color-e, #efeff5);
padding: 8px;
border-radius: 4px;
height: auto;
width: 100%;
box-sizing: border-box;
}
.adm-form-file {
display: flex;
flex-direction: column;
gap: 8px;
}
.adm-form-file>div {
display: flex;
gap: 8px;
align-items: center;
}
.adm-form-file div>span {
display: inline-block;
min-width: 80px;
font-size: 14px;
}
.adm-form-file div>input {
flex-grow: 1;
box-sizing: border-box;
border: 1px solid var(--theme-color-e, #efeff5);
padding: 8px;
border-radius: 4px;
height: auto;
}
.adm-form-file div>input[type=file] {
cursor: pointer;
}
.adm-form-listedit {
width: 100%;
}
.adm-form-listedit .adm-listedit-controls {
display: flex;
align-items: center;
gap: 8px;
}
.adm-listedit-items {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 8px;
overflow-y: auto;
max-height: 360px;
box-sizing: border-box;
border: 1px solid var(--theme-color-e, #efeff5);
border-radius: 4px;
padding: 8px;
}
.adm-listedit-item {
display: flex;
align-items: center;
gap: 8px;
}
.adm-form-listedit input[type=text] {
flex-grow: 1;
padding: 8px;
flex-grow: 1;
box-sizing: border-box;
border: 1px solid var(--theme-color-e, #efeff5);
border-radius: 4px;
}
.adm-listedit-remove,
.adm-listedit-add {
min-width: 100px;
align-self: stretch;
border: 1px solid #ddd;
background: #f8f8f8;
cursor: pointer;
border-radius: 4px;
font-size: 14px;
white-space: nowrap;
}
.adm-listedit-remove:hover,
.adm-listedit-add:hover {
background: #e8e8e8;
}
.adm-listedit-remove {
background: var(--theme-color-sub-b, #ff6b6b);
color: #000;
border-color: var(--theme-color-sub, #ff5252);
}
.adm-listedit-remove:hover {
color: #FFF;
background: var(--theme-color-sub, #ff6b6b);
}
.adm-listedit-add {
background: var(--theme-color-e, #4CAF50);
color: #000;
border-color: var(--theme-color-d, #45a049);
}
.adm-listedit-add:hover {
color: #FFF;
background: var(--theme-color-d, #45a049);
}
.adm-listedit-controls {
text-align: left;
}
.adm-form-number {
padding: 4px;
display: flex;
align-items: center;
gap: 8px
}
.adm-form-number input[type=number] {
border: 1px solid var(--theme-color-e, #efeff5);
padding: 8px;
border-radius: 4px;
height: auto;
width: 80px;
min-width: 60px;
box-sizing: border-box;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
<?php
define('G5_IS_ADMIN', true);
include_once "../../../common.php";
include_once G5_ADMIN_PATH . '/admin.lib.php';
if (isset($token)) {
$token = @htmlspecialchars(strip_tags($token), ENT_QUOTES);
}
EventHandler::triggerEvent("gnuboard.admin.load_common");

View file

@ -24,5 +24,4 @@ member_delete($mb['mb_id']);
if ($url)
goto_url("{$url}?{$qstr}&amp;w=u&amp;mb_id=$mb_id");
else
goto_url("./action_list.php?{$qstr}");
?>
goto_url("./index.php?{$qstr}");

View file

@ -24,5 +24,4 @@ for ($i = 0; $i < count($_POST['chk']); $i++) {
if ($msg)
alert($msg);
goto_url('./action_list.php?' . $qstr);
?>
goto_url('./index.php?' . $qstr);

View file

@ -1,5 +1,6 @@
<?php
include_once './_common.php';
auth_check($auth[$sub_menu], 'r');
if (!$s_year)
@ -76,8 +77,7 @@ for ($j = 0; $row = sql_fetch_array($log); $j++) {
</a>
</p>
<?php }
} ?>
}
include_once G5_PATH . "/tail.sub.php";
<?php
include_once '../tail.sub.php';
?>

View file

@ -3,7 +3,8 @@
* @var string|int $cf_reply_cnt
* @var string|int $s_mbid
*/
include_once './_common.php';
include_once "./_common.php";
auth_check($auth[$sub_menu], 'r');
$check_member = sql_fetch("select * from {$g5['member_table']} limit 0, 1");
@ -116,7 +117,7 @@ $total_page = ceil($total_count / $page_rows); // 전체 페이지 계산
$from_record = ($page - 1) * $page_rows; // 시작 열을 구함
$g5['title'] = '활동량 관리';
include_once './admin.head.php';
include_once G5_ADMIN_PATH . "/admin.head.php";
include_once G5_PLUGIN_PATH . '/jquery-ui/datepicker.php';
@ -296,7 +297,8 @@ if ($check_manner || $check_manner2) {
<th>
<?php echo subject_sort_link('wr_logs', 's_board=' . $s_board . '&s_date=' . $s_date . '&e_date=' . $e_date) ?>로그</a>
</th>
<th><?php echo subject_sort_link('wr_cms', 's_board=' . $s_board . '&s_date=' . $s_date . '&e_date=' . $e_date) ?>덧글</a>
<th>
<?php echo subject_sort_link('wr_cms', 's_board=' . $s_board . '&s_date=' . $s_date . '&e_date=' . $e_date) ?>덧글</a>
</th>
<?php if ($check_manner || $check_manner2) { ?>
<th>리플매너</th>
@ -305,7 +307,8 @@ if ($check_manner || $check_manner2) {
<th scope="col">
<?php echo subject_sort_link('mb.mb_today_login', 's_board=' . $s_board . '&s_date=' . $s_date . '&e_date=' . $e_date) ?>최종
접속</a></th>
접속</a>
</th>
<th scope="col">
<?php echo subject_sort_link('mb.mb_error_cnt', 's_board=' . $s_board . '&s_date=' . $s_date . '&e_date=' . $e_date) ?>누적경고</a>
</th>
@ -391,7 +394,7 @@ if ($check_manner || $check_manner2) {
var mb_id = $(obj).attr('data-mbid');
var sendData = { s_date: s_date, e_date: e_date, s_board: s_board, mb_id: mb_id };
var url = g5_url + "/adm/action_manner_search.php";
var url = g5_url + "/adm/items/action/action_manner_search.php";
$.ajax({
type: 'post'
@ -404,10 +407,6 @@ if ($check_manner || $check_manner2) {
}
});
}
</script>
<?php
include_once './admin.tail.php';
?>
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -0,0 +1,12 @@
<?php
define('G5_IS_ADMIN', true);
include_once "../../../common.php";
include_once G5_ADMIN_PATH . '/admin.lib.php';
if (isset($token)) {
$token = @htmlspecialchars(strip_tags($token), ENT_QUOTES);
}
EventHandler::triggerEvent("gnuboard.admin.load_common");

View file

@ -12,7 +12,7 @@ if (!$rows)
$rows = 100;
$g5['title'] = '접속로그 변환';
include_once "./admin.head.php";
include_once G5_ADMIN_PATH . "/admin.head.php";
?>
<div id="processing">
@ -27,7 +27,7 @@ include_once "./admin.head.php";
$.ajax({
method: "GET",
url: "./browscap_converter.php",
url: "./converter.php",
data: { rows: "<?php echo $rows; ?>" },
async: true,
cache: false,
@ -39,7 +39,5 @@ include_once "./admin.head.php";
});
});
</script>
<?php
include_once "./admin.tail.php";
?>
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -8,7 +8,7 @@ if ($is_admin != 'super')
alert('최고관리자만 접근 가능합니다.');
$g5['title'] = 'Browscap 업데이트';
include_once "./admin.head.php";
include_once G5_ADMIN_PATH . "/admin.head.php";
?>
<div id="processing">
@ -22,7 +22,7 @@ include_once "./admin.head.php";
$("#processing").html('<div class="update_processing"></div><p>Browscap 정보를 업데이트 중입니다.</p>');
$.ajax({
url: "./browscap_update.php",
url: "./update.php",
async: true,
cache: false,
dataType: "html",
@ -38,7 +38,5 @@ include_once "./admin.head.php";
});
});
</script>
<?php
include_once "./admin.tail.php";
?>
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -0,0 +1,12 @@
<?php
define('G5_IS_ADMIN', true);
include_once "../../../common.php";
include_once G5_ADMIN_PATH . '/admin.lib.php';
if (isset($token)) {
$token = @htmlspecialchars(strip_tags($token), ENT_QUOTES);
}
EventHandler::triggerEvent("gnuboard.admin.load_common");

View file

@ -0,0 +1,107 @@
<?php
include_once './_common.php';
include_once G5_EDITOR_LIB;
if ($is_admin != 'super') {
alert_close('최고관리자만 접근 가능합니다.');
}
if (!sql_fetch_array(sql_query("DESC {$g5['addons_config_table']}"))) {
sql_query("CREATE TABLE {$g5['addons_config_table']} (
addon_name VARCHAR(255) PRIMARY KEY,
addon_version VARCHAR(255),
addon_config TEXT
);");
}
$g5['title'] = "애드온 설정";
include_once G5_ADMIN_PATH . '/admin.head.php';
add_stylesheet(get_embed_file("css", G5_PATH . "/adm/css/addon_config.css"), 1);
?>
<form method="POST" action="./addon_config_update.php" class="addon_conf_form">
<section class="addon_config">
<nav><span>설치된 애드온 목록</span><?php
if (!empty(AddonLoader::$addons)) {
foreach (AddonLoader::$addons as $menu) {
$selected = isset($_GET["addon"]) && $_GET["addon"] == $menu->className ? " selected" : "";
echo "<a href=\"./addon_config.php?addon={$menu->className}\" class=\"addon_menu{$selected}\">{$menu->name}</a>";
}
} else {
echo "<a href=\"#\">설치된 애드온이 없습니다.</a>";
}
?></nav>
<section>
<?php
if (isset($_GET["addon"])) {
if (array_key_exists($_GET["addon"], AddonLoader::$addons)) {
$addon = AddonLoader::$addons[$addon];
?>
<header>
<div class="tbl_frm01 tbl_wrap">
<table>
<colgroup>
<col style="width: 140px;">
<col>
</colgroup>
<tbody>
<tr>
<th scope="row">
애드온 이름
</th>
<td>
<?= $addon->name ?>
</td>
</tr>
<tr>
<th scope="row">
애드온 제작자
</th>
<td>
<?= $addon->link ? "<a href=\"" . $addon->link . "\" target=\"_blank\">" . $addon->author . "</a> <span style=\"font-size: 11px\">[{$addon->link}]</span>" : $addon->author ?>
</td>
</tr>
<tr>
<th scope="row">
애드온 설명
</th>
<td>
<?= $addon->description ?>
</td>
</tr>
<tr>
<th scope="row">
애드온 버전
</th>
<td>
<?= $addon->version ?>
</td>
</tr>
</tbody>
</table>
</div>
</header>
<content>
<input type="hidden" name="addon" value="<?= $addon->className ?>" />
<?php
if (method_exists($addon, "printConfigForm")) {
$addon->printConfigForm();
}
?>
</content><?php
}
} else {
echo "<span class=\"empty\">애드온을 선택하세요</span>";
}
?>
</section>
</section>
<div class="btn_confirm">
<div class="btn">
<span class="material-icons">save</span>
<input type="submit" value="저장" class="btn_submit" accesskey="s">
</div>
</div>
</form>
<?php
include_once G5_ADMIN_PATH . '/admin.tail.php';

View file

@ -1,5 +1,5 @@
<?php
include_once __DIR__ . '/_common.php';
include_once './_common.php';
if ($is_admin != 'super') {
alert_close('최고관리자만 접근 가능합니다.');

View file

@ -19,10 +19,10 @@ if (!sql_fetch_array(sql_query("DESC {$g5['font_table']}"))) {
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3";
sql_query($sql, false);
sql_query("INSERT INTO `avo_editor_fonts`
sql_query("INSERT INTO `{$g5['font_table']}`
(`font_name`, `font_family`, `font_url`, `font_weight`, `font_style`)
VALUES ('에스코어드림', 'S-CoreDream-3Light', 'url(\'https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_six@1.2/S-CoreDream-3Light.woff\') format(\'woff\')', 'normal', 'normal');");
sql_query("INSERT INTO `avo_editor_fonts` (`font_name`, `font_family`, `font_url`, `font_weight`, `font_style`)
sql_query("INSERT INTO `{$g5['font_table']}` (`font_name`, `font_family`, `font_url`, `font_weight`, `font_style`)
VALUES ('평창평화체', 'PyeongChangPeace-Light', 'url(\'https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2206-02@1.0/PyeongChangPeace-Light.woff2\') format(\'woff2\')', '300', 'normal');");
}
@ -32,7 +32,7 @@ $result = sql_query($sql);
$g5['title'] = "에디터 폰트 관리";
include_once __DIR__ . '/admin.head.php';
include_once G5_ADMIN_PATH . "/admin.head.php";
EventHandler::triggerEvent("amber.admin.editor_font_form_before");
?>
@ -188,4 +188,4 @@ EventHandler::triggerEvent("amber.admin.editor_font_form_before");
</script>
<?php
EventHandler::triggerEvent("amber.admin.editor_font_form_after");
include_once __DIR__ . '/admin.tail.php';
include_once G5_ADMIN_PATH . '/admin.tail.php';

View file

@ -1,6 +1,5 @@
<?php
include_once "./_common.php";
include_once __DIR__ . '/_common.php';
if ($is_admin != 'super') {
alert('최고관리자만 접근 가능합니다.');

View file

@ -0,0 +1,177 @@
<?php
include_once __DIR__ . '/_common.php';
if ($is_admin != 'super')
alert_close('최고관리자만 접근 가능합니다.');
$g5['title'] = '메뉴 추가';
include_once G5_PATH . "/head.sub.php";
// 코드
if ($new == 'new' || !$code) {
$code = base_convert(substr($code, 0, 2), 36, 10);
$code += 36;
$code = base_convert($code, 10, 36);
}
?>
<style>
body {
min-width: 100%;
}
</style>
<div id="menu_frm" class="new_win">
<h1><?php echo $g5['title']; ?></h1>
<form name="fmenuform" id="fmenuform" enctype="multipart/form-data">
<div class="new_win_desc">
<label for="me_type">대상선택</label>
<select name="me_type" id="me_type">
<option value="">직접입력</option>
<option value="board">게시판</option>
<option value="content">페이지</option>
</select>
</div>
<div class="win-guide">구분선을 추가하실 경우, 메뉴 명에 <em>구분선</em>이라고 입력 추가 해주세요.</div>
<div id="menu_result"></div>
</form>
</div>
<script>
$(function () {
$("#menu_result").load(
"./menu_form_search.php"
);
$("#me_type").on("change", function () {
var type = $(this).val();
$("#menu_result").empty().load(
"./menu_form_search.php",
{ type: type }
);
});
$(document).on("click", "#add_manual", function () {
var me_name = $.trim($("#me_name").val());
var me_link = $.trim($("#me_link").val());
add_menu_list(me_name, me_link, "<?php echo $code; ?>");
});
$(document).on("click", ".add_select", function () {
var me_name = $.trim($(this).siblings("input[name='subject[]']").val());
var me_link = $.trim($(this).siblings("input[name='link[]']").val());
add_menu_list(me_name, me_link, "<?php echo $code; ?>");
});
});
function add_menu_list(name, link, code) {
const menulist = opener.document.getElementById('menulist');
const ms = new Date().getTime();
var sub_menu_class;
<?php if ($new == 'new') { ?>
sub_menu_class = " class=\"td_category\"";
<?php } else { ?>
sub_menu_class = " class=\"td_category sub_menu_class\"";
<?php } ?>
let list = `
<article class="menu_list menu_group_${code}"
data-name="${sub_menu_class}">
<div class="menu_reqset">
<div class="al_menu" style="width: 50px">
<span class="al_label">사용 여부</span>
<input type="checkbox" name="me_use[]" value="1" checked>
</div>
<div class="al_menu" style="width: 60px">
<span class="al_label">정렬 순서</span>
<input type="text" name="me_order[]" value="0"
class="frm_input full_input">
</div>
<div class="al_menu al_menu_name">
<span class="al_label">메뉴 이름</span>
<input type="hidden" name="code[]" value="${code}" />
<input type="hidden" name="me_level[]" value="" />
<input type="text" name="me_name[]" value="${name}" required
class="required frm_input full_input" />
</div>
<div class="al_menu al_menu_name">
<span class="al_label">링크</span>
<input type="text" name="me_link[]" value="${link}"
class="frm_input full_input" />
</div>
<div class="al_menu" style="width: 80px">
<span class="al_label">열릴 위치</span>
<select name="me_target[]" class=" frm_input full_input">
<option value="self" selected>현재창</option>
<option value="blank">새창</option>
</select>
</div>
<button type="button" class="btn_del_menu">
<span class='material-icons'>delete</span>
</button>
</div>
<div class="al_menu_listing">
<div class="al_menu" style="width: 50px">
<span class="al_label">메뉴 ID</span>
<div class="al_value">${code}</div>
</div>
<div class="al_menu" style="width: 60px">
<span class="al_label">부모 ID</span>
<input type="text" name="me_parent[]" value=""
class="frm_input full_input">
</div>
<div class="al_menu" style="width: 60px">
<span class="al_label">깊이</span>
<input type="text" name="me_depth[]" value="0"
class="frm_input full_input">
</div>
<div class="al_menu al_center" style="width: 60px">
<i class="material-icons"></i>
</div>
<div class="al_menu">
<span class="al_label">Material Icon</span>
<input type="text" name="me_icon[]" value=""
class=" frm_input full_input" />
</div>
<div class="al_menu al_center" style="width: 60px;">
</div>
<div class="al_menu">
<span class="al_label">통상 이미지</span>
<input type="file" name="me_img_file[]" class=" frm_input full_input"
style="width:80%">
</div>
<div class="al_menu al_fill">
<span class="al_label"><?= help('* 사용하지 않을 경우 공란으로 남겨두시면 됩니다.') ?></span>
<input type="text" name="me_img[]" value=""
class=" frm_input full_input" style="width:80%">
</div>
<div class="al_menu al_center" style="width: 60px;">
</div>
<div class="al_menu">
<span class="al_label">마우스 오버 이미지</span>
<input type="file" name="me_img2_file[]" class=" frm_input full_input"
style="width:80%">
</div>
<div class="al_menu al_fill">
<span class="al_label"><?= help('* 사용하지 않을 경우 공란으로 남겨두시면 됩니다.') ?></span>
<input type="text" name="me_img2[]" value=""
class=" frm_input full_input" style="width:80%">
</div>
</div>
</article>`;
menulist.innerHTML += list;
window.close();
}
</script>
<?php
include_once G5_PATH . '/tail.sub.php';
?>

View file

@ -1,5 +1,5 @@
<?php
include_once "./_common.php";
include_once __DIR__ . '/_common.php';
if ($is_admin != 'super')
die('최고관리자만 접근 가능합니다.');

View file

@ -0,0 +1,294 @@
<?php
include_once __DIR__ . '/_common.php';
if ($is_admin != 'super')
alert('최고관리자만 접근 가능합니다.');
$menu_update = sql_query("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '" . G5_MYSQL_DB . "' AND TABLE_NAME = '{$g5['menu_table']}'");
$columns = [];
while ($row = sql_fetch_array($menu_update)) {
$columns[] = $row["COLUMN_NAME"];
}
/* add menu depth */
if (!in_array("me_depth", $columns)) {
sql_query("ALTER TABLE {$g5['menu_table']} ADD COLUMN me_depth INT DEFAULT 0");
}
if (!in_array("me_parent", $columns)) {
sql_query("ALTER TABLE {$g5['menu_table']} ADD COLUMN me_parent VARCHAR(50) DEFAULT ''");
}
if (!in_array("me_img", $columns)) {
sql_query("ALTER TABLE {$g5['menu_table']} ADD COLUMN me_img VARCHAR(255) DEFAULT '' AFTER me_name");
}
if (!in_array("me_img2", $columns)) {
sql_query("ALTER TABLE {$g5['menu_table']} ADD COLUMN me_img2 VARCHAR(255) DEFAULT '' AFTER me_img");
}
$sql = "SELECT * FROM {$g5['menu_table']} order by me_order*1, me_id ";
$result = sql_query($sql);
$g5['title'] = "메뉴설정";
include_once G5_ADMIN_PATH . "/admin.head.php";
$colspan = 11;
?>
<style>
.tbl_wrap article {
display: flex;
flex-direction: column;
border: 1px solid #E0E0E0;
border-radius: 4px;
margin: 4px 0;
overflow: hidden;
}
article .menu_reqset {
display: flex;
padding: 8px;
gap: 8px;
justify-content: center;
align-items: center;
background: #F4F4F4;
}
.al_menu_listing {
display: flex;
padding: 8px;
gap: 8px;
}
article .menu_reqset .al_menu_name {
flex-grow: 1
}
article .menu_reqset button {
border: 1px solid #E0E0E0;
border-radius: 4px;
width: 48px;
height: 48px;
}
.al_menu {
display: flex;
flex-direction: column;
gap: 4px;
}
.al_menu .al_label {
line-height: 16px;
height: 16px;
}
.al_menu select,
.al_menu input {
height: 24px;
box-sizing: border-box;
}
.al_menu input[type=checkbox] {
height: 22px;
margin: 1px;
}
.al_menu_listing {
padding: 8px;
}
.al_center {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #E0E0E0;
background-size: cover;
}
.al_fill {
flex-grow: 1;
}
</style>
<div class="local_desc01 local_desc">
<p><strong>주의!</strong> 메뉴설정 작업 반드시 <strong>상단의 저장 버튼</strong> 누르셔야 저장됩니다.</p>
<p>아이콘 항목에 사용할 구글 아이콘 이름을 입력해주세요. ( ex. <span style="color:red">&lt;span
class="material-icons"&gt;<strong>home</strong>&lt;/span&gt;</span> <strong>home</strong> 입력하기 )</p>
</div>
<div class="local_desc01 local_desc">
<p>아이콘, 이미지 스킨이 지원하는 쪽이 출력됩니다. 라이트 계열의 스킨에서는 아이콘이, 퍼스널 계열의 스킨에서는 이미지가 출력됩니다.</p>
</div>
<form name="fmenulist" id="fmenulist" method="post" action="./menu_list_update.php"
onsubmit="return fmenulist_submit(this);" enctype="multipart/form-data">
<input type="hidden" name="token" value="">
<div class="btn_confirm">
<a href="https://fonts.google.com/icons?icon.query=house&icon.set=Material+Icons" target="_blank" class="btn ty3"
title="구글 아이콘 목록 보기"><span class="material-icons">app_registration</span></a>
<button type="button" onclick="return add_menu();" class="ty2"><span class="material-icons">add</span></button>
<div class="btn">
<span class="material-icons">save</span>
<input type="submit" value="저장" class="btn_submit" accesskey="s">
</div>
</div>
<div id="menulist" class="tbl_head01 tbl_wrap">
<?php
for ($i = 0; $row = sql_fetch_array($result); $i++) {
$bg = 'bg' . ($i % 2);
$sub_menu_class = '';
if (strlen($row['me_code']) == 4) {
$sub_menu_class = ' sub_menu_class';
$sub_menu_info = '<span class="sound_only">' . $row['me_name'] . '의 서브</span>';
$sub_menu_ico = '<span class="sub_menu_ico"></span>';
}
$search = ['"', "'"];
$replace = ['&#034;', '&#039;'];
$me_name = str_replace($search, $replace, $row['me_name']);
?>
<article class="<?php echo $bg; ?> menu_list menu_group_<?php echo substr($row['me_code'], 0, 2); ?>"
data-code="<?php echo substr($row['me_code'], 0, 2); ?>"
data-name="<?php echo $me_name; ?>">
<div class="menu_reqset">
<div class="al_menu" style="width: 50px">
<span class="al_label">사용 여부</span>
<input type="checkbox" name="me_use[]" id="me_use_<?php echo $i; ?>" value="1" <?= $row['me_use'] == 1 ? "checked" : ""; ?>>
</div>
<div class="al_menu" style="width: 60px">
<span class="al_label">정렬 순서</span>
<input type="text" name="me_order[]" value="<?php echo $row['me_order'] ?>" id="me_order_<?php echo $i; ?>"
class="frm_input full_input">
</div>
<div class="al_menu al_menu_name<?php echo $sub_menu_class; ?>">
<span class="al_label">메뉴 이름</span>
<input type="hidden" name="code[]" value="<?php echo substr($row['me_code'], 0, 2) ?>" />
<input type="hidden" name="me_level[]" value="<?php echo $row['me_level'] ?>" />
<input type="text" name="me_name[]" value="<?php echo get_sanitize_input($me_name); ?>" required
class="required frm_input full_input" />
</div>
<div class="al_menu al_menu_name<?php echo $sub_menu_class; ?>">
<span class="al_label">링크</span>
<input type="text" name="me_link[]" value="<?php echo $row['me_link'] ?>" id="me_link_<?php echo $i; ?>"
class="frm_input full_input" />
</div>
<div class="al_menu" style="width: 80px">
<span class="al_label">열릴 위치</span>
<select name="me_target[]" class=" frm_input full_input">
<option value="self" <?php echo get_selected($row['me_target'], 'self'); ?>>현재창</option>
<option value="blank" <?php echo get_selected($row['me_target'], 'blank'); ?>>새창</option>
</select>
</div>
<button type="button" class="btn_del_menu">
<span class='material-icons'>delete</span>
</button>
</div>
<div class="al_menu_listing">
<div class="al_menu" style="width: 50px">
<span class="al_label">메뉴 ID</span>
<div class="al_value"><?= $row['me_code'] ?></div>
</div>
<div class="al_menu" style="width: 60px">
<span class="al_label">부모 ID</span>
<input type="text" name="me_parent[]" value="<?= $row['me_parent'] ?>" id="me_parent_<?= $i ?>"
class="frm_input full_input">
</div>
<div class="al_menu" style="width: 60px">
<span class="al_label">깊이</span>
<input type="text" name="me_depth[]" value="<?= $row['me_depth'] ?>" id="me_depth_<?= $i ?>"
class="frm_input full_input">
</div>
<div class="al_menu al_center" style="width: 60px">
<i class="material-icons"><?= $row['me_icon'] ?></i>
</div>
<div class="al_menu">
<span class="al_label">Material Icon</span>
<input type="text" name="me_icon[]" value="<?php echo get_text($row['me_icon']) ?>"
class=" frm_input full_input" />
</div>
<div class="al_menu al_center" style="width: 60px; background-image: url('<?= $row['me_img'] ?>');">
</div>
<div class="al_menu">
<span class="al_label">통상 이미지</span>
<input type="file" name="me_img_file[]" id="me_img_file_<?php echo $i; ?>" class=" frm_input full_input"
style="width:80%">
</div>
<div class="al_menu al_fill">
<span class="al_label"><?= help('* 사용하지 않을 경우 공란으로 남겨두시면 됩니다.') ?></span>
<input type="text" name="me_img[]" value="<?php echo $row['me_img'] ?>" id="me_img_<?php echo $i; ?>"
class=" frm_input full_input" style="width:80%">
</div>
<div class="al_menu al_center" style="width: 60px; background-image: url('<?= $row['me_img2'] ?>');">
</div>
<div class="al_menu">
<span class="al_label">마우스 오버 이미지</span>
<input type="file" name="me_img2_file[]" id="me_img2_file_<?php echo $i; ?>" class=" frm_input full_input"
style="width:80%">
</div>
<div class="al_menu al_fill">
<span class="al_label"><?= help('* 사용하지 않을 경우 공란으로 남겨두시면 됩니다.') ?></span>
<input type="text" name="me_img2[]" value="<?php echo $row['me_img2'] ?>" id="me_img2_<?php echo $i; ?>"
class=" frm_input full_input" style="width:80%">
</div>
</div>
</article>
<?php
}
if ($i == 0)
echo '<tr id="empty_menu_list"><td colspan="' . $colspan . '" class="empty_table">자료가 없습니다.</td></tr>';
?>
</div>
</form>
<script>
$(function () {
$(document).on("click", ".btn_add_submenu", function () {
var code = $(this).closest("tr").find("input[name='code[]']").val().substr(0, 2);
add_submenu(code);
});
$(document).on("click", ".btn_del_menu", function () {
if (!confirm("메뉴를 삭제하시겠습니까?"))
return false;
$(this).parent().parent().remove();
});
});
function add_menu() {
var max_code = base_convert(0, 10, 36);
$("#menulist tr.menu_list").each(function () {
var me_code = $(this).find("input[name='code[]']").val().substr(0, 2);
if (max_code < me_code)
max_code = me_code;
});
var url = "./menu_form.php?code=" + max_code + "&new=new";
window.open(url, "add_menu", "left=100,top=100,width=550,height=650,scrollbars=yes,resizable=yes");
return false;
}
function add_submenu(code) {
var url = "./menu_form.php?code=" + code;
window.open(url, "add_menu", "left=100,top=100,width=550,height=650,scrollbars=yes,resizable=yes");
return false;
}
function base_convert(number, frombase, tobase) {
// discuss at: http://phpjs.org/functions/base_convert/
// original by: Philippe Baumann
// improved by: Rafał Kukawski (http://blog.kukawski.pl)
// example 1: base_convert('A37334', 16, 2);
// returns 1: '101000110111001100110100'
return parseInt(number + '', frombase | 0)
.toString(tobase | 0);
}
function fmenulist_submit(f) {
return true;
}
</script>
<?php
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -1,5 +1,5 @@
<?php
include_once "./_common.php";
include_once __DIR__ . '/_common.php';
check_demo();
@ -16,9 +16,44 @@ $group_code = null;
$primary_code = null;
$count = count($_POST['code']);
$site_path = G5_DATA_PATH . '/site';
$site_url = G5_DATA_URL . '/site';
@mkdir($site_path, G5_DIR_PERMISSION);
@chmod($site_path, G5_DIR_PERMISSION);
EventHandler::triggerEvent("amber.admin.menu_list_update_before");
for ($i = 0; $i < $count; $i++) {
$img_link = "";
$img_link2 = "";
$img_link = $_POST['me_img'][$i];
if ($_FILES['me_img_file']['name'][$i]) {
if (!preg_match("/\.(gif|jpg|png)$/i", $_FILES['me_img_file']['name'][$i])) {
alert("이미지가 gif, jpg, png 파일이 아닙니다.");
} else {
$exp = explode(".", $_FILES['me_img_file']['name'][$i]);
$exp = $exp[count($exp) - 1];
$image_name = time() . $i . "." . $exp;
upload_file($_FILES['me_img_file']['tmp_name'][$i], $image_name, $site_path);
$img_link = $site_url . "/" . $image_name;
}
}
$img_link2 = $_POST['me_img2'][$i];
if ($_FILES['me_img2_file']['name'][$i]) {
if (!preg_match("/\.(gif|jpg|png)$/i", $_FILES['me_img2_file']['name'][$i])) {
alert("이미지가 gif, jpg, png 파일이 아닙니다.");
} else {
$exp = explode(".", $_FILES['me_img2_file']['name'][$i]);
$exp = $exp[count($exp) - 1];
$image_name = time() . $i . "_o." . $exp;
upload_file($_FILES['me_img2_file']['tmp_name'][$i], $image_name, $site_path);
$img_link2 = $site_url . "/" . $image_name;
}
}
$_POST = array_map_deep('trim', $_POST);
if (preg_match('/^javascript/i', preg_replace('/[ ]{1,}|[\t]/', '', $_POST['me_link'][$i]))) {
$_POST['me_link'][$i] = G5_URL;
@ -63,9 +98,11 @@ for ($i = 0; $i < $count; $i++) {
// 메뉴 등록
$sql = "INSERT INTO {$g5['menu_table']}
SET me_code = '{$me_code}',
me_icon = '{$_POST['me_icon'][$i]}',
me_name = '{$me_name}',
me_link = '{$me_link}',
me_img = '{$img_link}',
me_img2 = '{$img_link2}',
me_icon = '{$_POST['me_icon'][$i]}',
me_target = '" . sql_real_escape_string(strip_tags($_POST['me_target'][$i])) . "',
me_order = '" . sql_real_escape_string(strip_tags($_POST['me_order'][$i])) . "',
me_use = '" . sql_real_escape_string(strip_tags($_POST['me_use'][$i])) . "',

View file

@ -0,0 +1,9 @@
<?php
define('G5_IS_ADMIN', true);
include_once "../../../common.php";
require_once G5_ADMIN_PATH . '/admin.lib.php';
include_once G5_ADMIN_PATH . "/admin.head.php";
if (isset($token)) {
$token = @htmlspecialchars(strip_tags($token), ENT_QUOTES);
}
EventHandler::triggerEvent("gnuboard.admin.load_common");

View file

@ -91,4 +91,4 @@ while ($row = sql_fetch_array($result)) {
</table>
</div>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -86,4 +86,4 @@ for ($i = 0; $row = sql_fetch_array($result); $i++) {
</table>
</div>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -110,4 +110,4 @@ $now_year = (int) substr(G5_TIME_YMD, 0, 4);
}
</script>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -95,4 +95,4 @@ while ($row = sql_fetch_array($result)) {
</table>
</div>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -98,5 +98,4 @@ while ($row = sql_fetch_array($result)) {
</table>
</div>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -76,4 +76,4 @@ for ($i = 0; $row = sql_fetch_array($result); $i++) {
</table>
</div>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -117,5 +117,5 @@ $qstr .= "&amp;page=";
$pagelist = get_paging($config['cf_write_pages'], $page, $total_page, "{$_SERVER['SCRIPT_NAME']}?$qstr");
echo $pagelist;
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -86,4 +86,4 @@ for ($i = 0; $row = sql_fetch_array($result); $i++) {
</table>
</div>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -96,4 +96,4 @@ while ($row = sql_fetch_array($result)) {
</table>
</div>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -146,4 +146,4 @@ if ($pagelist) {
}
</script>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -74,4 +74,4 @@ for ($i = 0; $row = sql_fetch_array($result); $i++) {
</table>
</div>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -86,5 +86,5 @@ for ($i = 0; $row = sql_fetch_array($result); $i++) {
</table>
</div>
<?php
include_once "./admin.tail.php";
include_once G5_ADMIN_PATH . "/admin.tail.php";

View file

@ -1,152 +0,0 @@
<?php
include_once "./_common.php";
if ($is_admin != 'super')
alert_close('최고관리자만 접근 가능합니다.');
$g5['title'] = '메뉴 추가';
include_once G5_PATH . "/head.sub.php";
// 코드
if ($new == 'new' || !$code) {
$code = base_convert(substr($code, 0, 2), 36, 10);
$code += 36;
$code = base_convert($code, 10, 36);
}
?>
<style>
body {
min-width: 100%;
}
</style>
<div id="menu_frm" class="new_win">
<h1><?php echo $g5['title']; ?></h1>
<form name="fmenuform" id="fmenuform" enctype="multipart/form-data">
<div class="new_win_desc">
<label for="me_type">대상선택</label>
<select name="me_type" id="me_type">
<option value="">직접입력</option>
<option value="board">게시판</option>
<option value="content">페이지</option>
</select>
</div>
<div class="win-guide">구분선을 추가하실 경우, 메뉴 명에 <em>구분선</em>이라고 입력 추가 해주세요.</div>
<div id="menu_result"></div>
</form>
</div>
<script>
$(function () {
$("#menu_result").load(
"./menu_form_search.php"
);
$("#me_type").on("change", function () {
var type = $(this).val();
$("#menu_result").empty().load(
"./menu_form_search.php",
{ type: type }
);
});
$(document).on("click", "#add_manual", function () {
var me_name = $.trim($("#me_name").val());
var me_link = $.trim($("#me_link").val());
add_menu_list(me_name, me_link, "<?php echo $code; ?>");
});
$(document).on("click", ".add_select", function () {
var me_name = $.trim($(this).siblings("input[name='subject[]']").val());
var me_link = $.trim($(this).siblings("input[name='link[]']").val());
add_menu_list(me_name, me_link, "<?php echo $code; ?>");
});
});
function add_menu_list(name, link, code) {
var $menulist = $("#menulist", opener.document);
var ms = new Date().getTime();
var sub_menu_class;
<?php if ($new == 'new') { ?>
sub_menu_class = " class=\"td_category\"";
<?php } else { ?>
sub_menu_class = " class=\"td_category sub_menu_class\"";
<?php } ?>
var list = "";
list += "<tr class=\"menu_list menu_group_<?php echo $code; ?>\" data-name='" + name + "'>";
list += "<td" + sub_menu_class + ">";
list += " <input type=\"hidden\" name=\"code[]\" value=\"<?php echo $code; ?>\" />";
list += " <input type=\"hidden\" name=\"me_level[]\" value=\"\" />";
list += " <input type=\"text\" name=\"me_name[]\" value=\"" + name + "\" id=\"me_name_" + ms + "\" required class=\"required frm_input full_input\" />";
list += "</td>";
list += "<td class=\"td_numsmall\">";
list += " ";
list += "</td>";
list += "<td class=\"td_numsmall\">";
list += " <input type=\"text\" name=\"me_parent[]\" value=\"\" class=\"frm_input\" size=\"5\">";
list += "</td>";
list += "<td class=\"td_numsmall\">";
list += " <input type=\"text\" name=\"me_depth[]\" value=\"0\" class=\"frm_input\" size=\"5\">";
list += "</td>";
list += "<td></td>";
list += "<td>";
list += " <input type=\"text\" name=\"me_icon[]\" class=\"frm_input full_input\" />";
list += "</td>";
list += "<td>";
list += " <input type=\"text\" name=\"me_link[]\" value=\"" + link + "\" class=\"frm_input full_input\" />";
list += "</td>";
list += "<td class=\"td_mng\">";
list += " <select name=\"me_target[]\">";
list += " <option value=\"self\">현재창</option>";
list += " <option value=\"blank\">새창</option>";
list += " </select>";
list += "</td>";
list += "<td class=\"td_numsmall order\">";
list += " <input type=\"text\" name=\"me_order[]\" value=\"0\" required class=\"required frm_input\" size=\"5\">";
list += "</td>";
list += "<td class=\"td_numsmall\">";
list += " <input type=\"checkbox\" name=\"me_use[]\" value=\"1\" class=\"frm_input\" checked>";
list += "</td>";
list += "<td class=\"td_mngsmall\">";
list += " <button type=\"button\" class=\"btn_del_menu\"><span class=''><span class='material-icons'>delete</span></button>";
list += "</td>";
list += "</tr>";
var $menu_last = null;
if (code)
$menu_last = $menulist.find("tr.menu_group_" + code + ":last");
else
$menu_last = $menulist.find("tr.menu_list:last");
if ($menu_last.size() > 0) {
$menu_last.after(list);
} else {
if ($menulist.find("#empty_menu_list").size() > 0)
$menulist.find("#empty_menu_list").remove();
$menulist.find("table tbody").append(list);
}
$menulist.find("tr.menu_list").each(function (index) {
$(this).removeClass("bg0 bg1")
.addClass("bg" + (index % 2));
});
window.close();
}
</script>
<?php
include_once G5_PATH . '/tail.sub.php';
?>

View file

@ -1,220 +0,0 @@
<?php
include_once "./_common.php";
if ($is_admin != 'super')
alert('최고관리자만 접근 가능합니다.');
$menu_update = sql_query("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '" . G5_MYSQL_DB . "' AND TABLE_NAME = '{$g5['menu_table']}'");
$columns = [];
while ($row = sql_fetch_array($menu_update)) {
$columns[] = $row["COLUMN_NAME"];
}
/* add menu depth */
if (!in_array("me_depth", $columns)) {
sql_query("ALTER TABLE {$g5['menu_table']} ADD COLUMN me_depth INT DEFAULT 0");
}
if (!in_array("me_parent", $columns)) {
sql_query("ALTER TABLE {$g5['menu_table']} ADD COLUMN me_parent VARCHAR(50) DEFAULT ''");
}
$sql = "SELECT * FROM {$g5['menu_table']} order by me_order*1, me_id ";
$result = sql_query($sql);
$g5['title'] = "메뉴설정";
include_once "./admin.head.php";
$colspan = 11;
?>
<div class="local_desc01 local_desc">
<p><strong>주의!</strong> 메뉴설정 작업 반드시 <strong>확인</strong> 누르셔야 저장됩니다.</p>
</div>
<div class="local_desc01 local_desc">
<p>아이콘 항목에 사용할 구글 아이콘 이름을 입력해주세요. ( ex. <span style="color:red">&lt;span
class="material-icons"&gt;<strong>home</strong>&lt;/span&gt;</span> <strong>home</strong> 입력하기 )</p>
</div>
<form name="fmenulist" id="fmenulist" method="post" action="./menu_list_update.php"
onsubmit="return fmenulist_submit(this);" enctype="multipart/form-data">
<input type="hidden" name="token" value="">
<div class="btn_confirm">
<a href="https://fonts.google.com/icons?icon.query=house&icon.set=Material+Icons" target="_blank" class="btn ty3"
title="구글 아이콘 목록 보기"><span class="material-icons">app_registration</span></a>
<button type="button" onclick="return add_menu();" class="ty2"><span class="material-icons">add</span></button>
<div class="btn">
<span class="material-icons">save</span>
<input type="submit" value="저장" class="btn_submit" accesskey="s">
</div>
</div>
<div id="menulist" class="tbl_head01 tbl_wrap">
<table>
<caption><?php echo $g5['title']; ?> 목록</caption>
<colgroup>
<col style="width:140px;">
<col style="width:80px;">
<col style="width:80px;">
<col style="width:80px;">
<col style="width:50px;">
<col style="width:150px;">
<col>
<col style="width:100px;">
<col style="width:80px;">
<col style="width:80px;">
<col style="width:80px;">
</colgroup>
<thead>
<tr>
<th scope="col">메뉴</th>
<th scope="col">ID</th>
<th scope="col">부모 ID</th>
<th scope="col">깊이</th>
<th scope="col" colspan="2">아이콘</th>
<th scope="col">링크</th>
<th scope="col">새창</th>
<th scope="col">순서</th>
<th scope="col">사용</th>
<th scope="col">관리</th>
</tr>
</thead>
<tbody>
<?php
for ($i = 0; $row = sql_fetch_array($result); $i++) {
$bg = 'bg' . ($i % 2);
$sub_menu_class = '';
if (strlen($row['me_code']) == 4) {
$sub_menu_class = ' sub_menu_class';
$sub_menu_info = '<span class="sound_only">' . $row['me_name'] . '의 서브</span>';
$sub_menu_ico = '<span class="sub_menu_ico"></span>';
}
$search = ['"', "'"];
$replace = ['&#034;', '&#039;'];
$me_name = str_replace($search, $replace, $row['me_name']);
?>
<tr class="<?php echo $bg; ?> menu_list menu_group_<?php echo substr($row['me_code'], 0, 2); ?>"
data-name="<?php echo $me_name; ?>">
<td class="td_category<?php echo $sub_menu_class; ?>">
<input type="hidden" name="code[]" value="<?php echo substr($row['me_code'], 0, 2) ?>" />
<input type="hidden" name="me_level[]" value="<?php echo $row['me_level'] ?>" />
<input type="text" name="me_name[]" value="<?php echo get_sanitize_input($me_name); ?>" required
class="required frm_input full_input" />
</td>
<td class="td_mng">
<?=$row['me_code']?>
</td>
<td class="td_mng">
<input type="text" name="me_parent[]" value="<?=$row['me_parent']?>" id="me_parent_<?=$i?>" class="frm_input full_input">
</td>
<td class="td_mng">
<input type="text" name="me_depth[]" value="<?=$row['me_depth']?>" id="me_depth_<?=$i?>" class="frm_input full_input">
</td>
<td>
<i class="material-icons"><?= $row['me_icon'] ?></i>
</td>
<td class="txt-left">
<input type="text" name="me_icon[]" value="<?php echo get_text($row['me_icon']) ?>"
class=" frm_input full_input" />
</td>
<td>
<input type="text" name="me_link[]" value="<?php echo $row['me_link'] ?>" id="me_link_<?php echo $i; ?>"
class="frm_input full_input" />
</td>
<td class="td_mng">
<select name="me_target[]" class=" frm_input full_input">
<option value="self" <?php echo get_selected($row['me_target'], 'self'); ?>>현재창</option>
<option value="blank" <?php echo get_selected($row['me_target'], 'blank'); ?>>새창</option>
</select>
</td>
<td class="td_num order">
<input type="text" name="me_order[]" value="<?php echo $row['me_order'] ?>" id="me_order_<?php echo $i; ?>"
class="frm_input full_input">
</td>
<td class="td_mng">
<input type="checkbox" name="me_use[]" id="me_use_<?php echo $i; ?>" value="1" <?= $row['me_use'] == 1 ? "checked" : ""; ?>>
</td>
<td class="td_mng">
<button type="button" class="btn_del_menu"><span class='material-icons'>delete</span></button>
</td>
</tr>
<?php
}
if ($i == 0)
echo '<tr id="empty_menu_list"><td colspan="' . $colspan . '" class="empty_table">자료가 없습니다.</td></tr>';
?>
</tbody>
</table>
</div>
</form>
<script>
$(function () {
$(document).on("click", ".btn_add_submenu", function () {
var code = $(this).closest("tr").find("input[name='code[]']").val().substr(0, 2);
add_submenu(code);
});
$(document).on("click", ".btn_del_menu", function () {
if (!confirm("메뉴를 삭제하시겠습니까?"))
return false;
var $tr = $(this).closest("tr");
if ($tr.find("td.sub_menu_class").size() > 0) {
$tr.remove();
} else {
var code = $(this).closest("tr").find("input[name='code[]']").val().substr(0, 2);
$("tr.menu_group_" + code).remove();
}
if ($("#menulist tr.menu_list").size() < 1) {
var list = "<tr id=\"empty_menu_list\"><td colspan=\"<?php echo $colspan; ?>\" class=\"empty_table\">자료가 없습니다.</td></tr>\n";
$("#menulist table tbody").append(list);
} else {
$("#menulist tr.menu_list").each(function (index) {
$(this).removeClass("bg0 bg1")
.addClass("bg" + (index % 2));
});
}
});
});
function add_menu() {
var max_code = base_convert(0, 10, 36);
$("#menulist tr.menu_list").each(function () {
var me_code = $(this).find("input[name='code[]']").val().substr(0, 2);
if (max_code < me_code)
max_code = me_code;
});
var url = "./menu_form.php?code=" + max_code + "&new=new";
window.open(url, "add_menu", "left=100,top=100,width=550,height=650,scrollbars=yes,resizable=yes");
return false;
}
function add_submenu(code) {
var url = "./menu_form.php?code=" + code;
window.open(url, "add_menu", "left=100,top=100,width=550,height=650,scrollbars=yes,resizable=yes");
return false;
}
function base_convert(number, frombase, tobase) {
// discuss at: http://phpjs.org/functions/base_convert/
// original by: Philippe Baumann
// improved by: Rafał Kukawski (http://blog.kukawski.pl)
// example 1: base_convert('A37334', 16, 2);
// returns 1: '101000110111001100110100'
return parseInt(number + '', frombase | 0)
.toString(tobase | 0);
}
function fmenulist_submit(f) {
return true;
}
</script>
<?php
include_once "./admin.tail.php";
?>

View file

@ -0,0 +1,12 @@
<?php
define('G5_IS_ADMIN', true);
include_once "../../common.php";
include_once G5_ADMIN_PATH . '/admin.lib.php';
if (isset($token)) {
$token = @htmlspecialchars(strip_tags($token), ENT_QUOTES);
}
EventHandler::triggerEvent("gnuboard.admin.load_common");

View file

@ -36,7 +36,7 @@ if ($is_admin && $is_admin == "super") {
}
if (!sql_table_exists($g5["article_table"])) {
sql_query("CREATE TABLE IF NOT EXISTS `avo_article` (
sql_query("CREATE TABLE IF NOT EXISTS `{$g5["article_table"]}` (
`ar_id` INT(11) NOT NULL AUTO_INCREMENT,
`ar_theme` VARCHAR(255) NOT NULL DEFAULT '',
`ar_code` VARCHAR(255) NOT NULL DEFAULT '',
@ -53,7 +53,7 @@ if ($is_admin && $is_admin == "super") {
}
if (!sql_table_exists($g5["article_default_table"])) {
sql_query("CREATE TABLE IF NOT EXISTS `avo_article_default` (
sql_query("CREATE TABLE IF NOT EXISTS `{$g5["article_default_table"]}` (
`ad_id` INT(11) NOT NULL AUTO_INCREMENT ,
`ad_use_thumb` INT(11) NOT NULL DEFAULT '0',
`ad_use_head` INT(11) NOT NULL DEFAULT '0',
@ -83,7 +83,7 @@ if ($is_admin && $is_admin == "super") {
}
if (!sql_table_exists($g5["value_table"])) {
sql_query("CREATE TABLE IF NOT EXISTS `avo_article_value` (
sql_query("CREATE TABLE IF NOT EXISTS `{$g5["value_table"]}` (
`av_id` INT(11) NOT NULL AUTO_INCREMENT ,
`ch_id` INT(11) NOT NULL DEFAULT '0',
`ar_theme` VARCHAR(255) NOT NULL DEFAULT '',

View file

@ -231,8 +231,9 @@ $g5['title'] = '환경설정';
include_once "./admin.head.php";
$pg_anchor = '<ul class="anchor">
<li><a href="#anc_001">기본환경</a></li>
<li><a href="#anc_002">게시판/회원</a></li>
<li><a href="#anc_001">서버정보</a></li>
<li><a href="#anc_002">기본환경</a></li>
<li><a href="#anc_003">게시판/회원</a></li>
<li><a href="#anc_010">레이아웃 추가설정</a></li>
</ul>';
@ -244,7 +245,157 @@ if (!$config['cf_icode_server_port'])
if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
$userinfo = get_icode_userinfo($config['cf_icode_id'], $config['cf_icode_pw']);
}
function getDiskUsage($path = '/')
{
$bytes = disk_total_space($path);
$free = disk_free_space($path);
$used = $bytes - $free;
return [
'total' => $bytes,
'free' => $free,
'used' => $used,
'usage_percent' => round(($used / $bytes) * 100, 2)
];
}
function formatBytes($bytes, $precision = 2)
{
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
$bytes /= 1024;
}
return round($bytes, $precision) . ' ' . $units[$i];
}
function getWebServerDiskUsage()
{
// $documentRoot = $_SERVER['DOCUMENT_ROOT'] ?? '/var/www/html';
return getDiskUsage();
}
function getNetworkTraffic()
{
// G5_PATH의 마지막 폴더명 확인
$pathParts = explode('/', rtrim(G5_PATH, '/'));
$lastFolder = end($pathParts);
if ($lastFolder === 'AvocadoAmber') {
$netJsonPath = dirname(G5_PATH) . '/net.json';
if (file_exists($netJsonPath)) {
$jsonContent = file_get_contents($netJsonPath);
$data = json_decode($jsonContent, true);
if ($data && isset($data['interfaces'][0]['traffic']['fiveminute'])) {
$fiveminute = $data['interfaces'][0]['traffic']['fiveminute'];
if (count($fiveminute) > 0) {
// 현재 날짜 (오늘)
$today = getdate();
$todayYear = $today['year'];
$todayMonth = $today['mon'];
$todayDay = $today['mday'];
$rx = 0;
$tx = 0;
// fiveminute 데이터에서 오늘 날짜와 일치하는 데이터만 합산
foreach ($fiveminute as $entry) {
$entryYear = $entry['date']['year'];
$entryMonth = $entry['date']['month'];
$entryDay = $entry['date']['day'];
$entryHour = $entry['time']['hour'];
$entryMinute = $entry['time']['minute'];
// 오늘 날짜와 일치하고, 0시 0분이 아닌 경우만 합산
if (
$entryYear == $todayYear &&
$entryMonth == $todayMonth &&
$entryDay == $todayDay &&
!($entryHour == 0 && $entryMinute == 0)
) {
$rx += $entry['rx'];
$tx += $entry['tx'];
}
}
$total = $rx + $tx;
// 일일 최대 트래픽 35GB (바이트로 변환)
$maxTraffic = 35 * 1024 * 1024 * 1024;
$usagePercent = round(($total / $maxTraffic) * 100, 2);
// 오늘 날짜 정보
$todayDate = $todayYear . '-' .
str_pad($todayMonth, 2, '0', STR_PAD_LEFT) . '-' .
str_pad($todayDay, 2, '0', STR_PAD_LEFT);
return [
'rx' => $rx,
'tx' => $tx,
'total' => $total,
'max' => $maxTraffic,
'usage_percent' => $usagePercent,
'date' => $todayDate,
'available' => true
];
}
}
}
}
return ['available' => false];
}
$webDiskUsage = getWebServerDiskUsage();
$networkTraffic = getNetworkTraffic();
?>
<style>
.server-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.server-info-item {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.server-info-item h3 {
margin: 0 0 15px 0;
font-size: 16px;
font-weight: bold;
color: #333;
}
.chart-container {
position: relative;
height: 200px;
margin-bottom: 15px;
}
.info-text {
font-size: 13px;
line-height: 1.6;
color: #666;
}
.info-text strong {
color: #333;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<form name="fconfigform" id="fconfigform" method="post" onsubmit="return fconfigform_submit(this);"
enctype="multipart/form-data">
<input type="hidden" name="token" value="" id="token">
@ -255,173 +406,192 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
</div>
</div>
<section id="anc_001">
<h2 class="h2_frm">서버 정보</h2>
<?php echo $pg_anchor ?>
<div class="server-info">
<!-- 디스크 용량 -->
<div class="server-info-item">
<h3>디스크 용량</h3>
<div class="chart-container">
<canvas id="diskChart"></canvas>
</div>
<div class="info-text">
<strong> 용량:</strong> <?php echo formatBytes($webDiskUsage['total']); ?><br>
<strong>사용 :</strong> <?php echo formatBytes($webDiskUsage['used']); ?><br>
<strong>사용 가능:</strong> <?php echo formatBytes($webDiskUsage['free']); ?><br>
<strong>사용률:</strong> <?php echo $webDiskUsage['usage_percent']; ?>%
</div>
</div>
<?php if ($networkTraffic['available']): ?>
<!-- 일일 트래픽 -->
<div class="server-info-item">
<h3>일일 트래픽 (<?php echo $networkTraffic['date']; ?>)</h3>
<div class="chart-container">
<canvas id="trafficChart"></canvas>
</div>
<div class="info-text">
<strong>수신(RX):</strong> <?php echo formatBytes($networkTraffic['rx']); ?><br>
<strong>송신(TX):</strong> <?php echo formatBytes($networkTraffic['tx']); ?><br>
<strong> 사용량:</strong> <?php echo formatBytes($networkTraffic['total']); ?><br>
<strong>일일 한도:</strong> <?php echo formatBytes($networkTraffic['max']); ?><br>
<strong>사용률:</strong> <?php echo $networkTraffic['usage_percent']; ?>%
</div>
</div>
<?php endif; ?>
</div>
</section>
<script>
// 디스크 용량 차트
const diskCtx = document.getElementById('diskChart').getContext('2d');
new Chart(diskCtx, {
type: 'pie',
data: {
labels: ['사용 중', '사용 가능'],
datasets: [{
data: [
<?php echo $webDiskUsage['used']; ?>,
<?php echo $webDiskUsage['free']; ?>
],
backgroundColor: [
'rgba(255, 99, 132, 0.8)',
'rgba(75, 192, 192, 0.8)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(75, 192, 192, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
},
tooltip: {
callbacks: {
label: function (context) {
const label = context.label || '';
const value = context.parsed;
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = ((value / total) * 100).toFixed(2);
// 바이트를 GB로 변환
const gb = (value / (1024 * 1024 * 1024)).toFixed(2);
return label + ': ' + gb + ' GB (' + percentage + '%)';
}
}
}
}
}
});
<?php if ($networkTraffic['available']): ?>
// 트래픽 차트
const trafficCtx = document.getElementById('trafficChart').getContext('2d');
new Chart(trafficCtx, {
type: 'pie',
data: {
labels: ['사용량', '남은 용량'],
datasets: [{
data: [
<?php echo $networkTraffic['total']; ?>,
<?php echo max(0, $networkTraffic['max'] - $networkTraffic['total']); ?>
],
backgroundColor: [
'rgba(54, 162, 235, 0.8)',
'rgba(201, 203, 207, 0.8)'
],
borderColor: [
'rgba(54, 162, 235, 1)',
'rgba(201, 203, 207, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
},
tooltip: {
callbacks: {
label: function (context) {
const label = context.label || '';
const value = context.parsed;
const total = <?php echo $networkTraffic['max']; ?>;
const percentage = ((value / total) * 100).toFixed(2);
// 바이트를 GB로 변환
const gb = (value / (1024 * 1024 * 1024)).toFixed(2);
return label + ': ' + gb + ' GB (' + percentage + '%)';
}
}
}
}
}
});
<?php endif; ?>
</script>
<section id="anc_002">
<h2 class="h2_frm">홈페이지 기본환경 설정</h2>
<?php echo $pg_anchor ?>
<div class="tbl_frm01 tbl_wrap">
<table>
<caption>홈페이지 기본환경 설정</caption>
<colgroup>
<col class="grid_4">
<col class="grid_10">
<col class="grid_4">
<col>
</colgroup>
<tbody>
<tr>
<th scope="row"><label for="cf_admin">최고관리자<strong class="sound_only">필수</strong></label></th>
<td><?php echo get_member_id_select('cf_admin', 10, $config['cf_admin'], 'required') ?></td>
<th scope="row">공개설정</th>
<td>
<input type="checkbox" name="cf_open" value="1" id="cf_open" <?php echo $config['cf_open'] ? 'checked' : ''; ?>>
<label for="cf_open">사이트공개</label>
&nbsp;&nbsp;
<input type="checkbox" name="cf_1" value="1" id="cf_1" <?php echo $config['cf_1'] ? 'checked' : ''; ?>>
<label for="cf_1">계정생성 가능</label>
</td>
</tr>
<tr>
<th scope="row">홈페이지 제목</th>
<td>
<input type="text" name="cf_title" value="<?php echo $config['cf_title'] ?>" id="cf_title" required
class="required" size="40">
</td>
<th>사이트설명</th>
<td>
<input type="text" name="cf_site_descript" value="<?php echo $config['cf_site_descript'] ?>" size="50" />
</td>
</tr>
<tr>
<th>커뮤니티 기능 사용</th>
<td colspan="3">
<?php echo help('데이터베이스를 설정했더라도 사용하지 않음 상태인 경우 관련 메뉴가 출력되지 않습니다.') ?>
<input type="checkbox" name="cf_community" value="1" id="cf_community" <?php echo $config['cf_community'] ? 'checked' : ''; ?>>
</td>
</tr>
<tr>
<th>파비콘</th>
<td colspan="3">
<?php echo help('파비콘 확장자는 ico 로 등록해 주셔야 적용됩니다.') ?>
직접등록&nbsp;&nbsp; <input type="file" name="cf_favicon_file" value="" size="50"
style="border:1px solid #ddd;">
&nbsp;&nbsp;
외부경로&nbsp;&nbsp; <input type="text" name="cf_favicon" value="<?= $config['cf_favicon'] ?>" size="50" />
</td>
</tr>
<tr>
<th>커서</th>
<td colspan="3">
<?php echo help('홈페이지의 커서로 사용할 이미지를 등록해주세요.') ?>
직접등록&nbsp;&nbsp; <input type="file" name="cf_cursor_file" value="" size="50">
&nbsp;&nbsp;
외부경로&nbsp;&nbsp; <input type="text" name="cf_cursor" value="<?= $config['cf_cursor'] ?>" size="50" />
</td>
</tr>
<tr>
<th>사이트이미지</th>
<td colspan="3">
<?php echo help('사이트 링크 추가시, SNS에서 미리보기로 뜨는 썸네일 이미지를 등록합니다. 290px * 160px 파일로 업로드해 주시길 바랍니다.') ?>
직접등록&nbsp;&nbsp; <input type="file" name="cf_site_img_file" value="" size="50">
&nbsp;&nbsp;
외부경로&nbsp;&nbsp; <input type="text" name="cf_site_img" value="<?= $config['cf_site_img'] ?>" size="50" />
</td>
</tr>
<tr>
<th scope="row"><label for="site_back">배경음악</label></th>
<td colspan="3">
<?php echo help('유튜브 재생목록 아이디 (https://www.youtube.com/watch?list=재생목록고유아이디) 를 입력해 주세요.') ?>
<input type="text" name="cf_bgm" value="<?php echo $config['cf_bgm'] ?>" id="cf_bgm" size="50">
</td>
</tr>
<tr>
<th scope="row"><label for="cf_possible_ip">접근가능 IP</label></th>
<td colspan="3">
<?php echo help('입력된 IP의 컴퓨터만 접근할 수 있습니다.<br>123.123.+ 도 입력 가능. (엔터로 구분)') ?>
<textarea name="cf_possible_ip" id="cf_possible_ip" rows="2"
style="height:100px;"><?php echo $config['cf_possible_ip'] ?></textarea>
</td>
</tr>
<tr>
<th scope="row"><label for="cf_intercept_ip">접근차단 IP</label></th>
<td colspan="3">
<?php echo help('입력된 IP의 컴퓨터는 접근할 수 없음.<br>123.123.+ 도 입력 가능. (엔터로 구분)') ?>
<textarea name="cf_intercept_ip" id="cf_intercept_ip" rows="2"
style="height:100px;"><?php echo $config['cf_intercept_ip'] ?></textarea>
</td>
</tr>
<tr>
<th>접속설정</th>
<td colspan="3">
<?php echo help('로그인이 제대로 안된다거나 화면이 안나오다 나올때 설정하세요') ?>
<input type="checkbox" name="cf_use_http" value="1" id="cf_use_http" <?php echo $config['cf_use_http'] ? 'checked' : ''; ?>>
<label for="cf_use_http">http:// 고정하기</label>
</td>
</tr>
</tbody>
</table>
<?php
$sql = "SELECT mb_id, mb_nick FROM {$g5['member_table']} WHERE mb_level >= '{$level}' ";
$accounts = sql_query($sql);
$accountList = [];
while ($row = sql_fetch_array($accounts)) {
$accountList[$row['mb_id']] = "{$row['mb_nick']} ({$row['mb_id']})";
}
setOptionList("최고관리자", "홈페이지의 최고 관리자 계정을 지정합니다.", $accountList, "cf_admin", '', $config, true);
setTextInput("홈페이지 이름", "", "cf_title", $config);
setTextInput("홈페이지 설명", "", "cf_site_descript", $config);
setCheckbox("홈페이지 공개", "로그인을 하지 않아도 홈페이지를 확인할 수 있도록 설정합니다.", "cf_open", "1", $config);
setCheckbox("계정 생성", "홈페이지 가입이 가능하도록 설정합니다.", "cf_1", "1", $config);
setCheckbox("커뮤니티 기능", "홈페이지 내에 커뮤니티 관련 기능을 활성화 합니다.<br>데이터베이스를 설정했더라도 <b>사용하지 않음</b> 상태인 경우 관련 메뉴가 출력되지 않습니다.", "cf_community", "1", $config);
setImageFile("파비콘 설정", "홈페이지에 적용할 파비콘 이미지를 설정합니다.", "cf_favicon", $config);
setImageFile("커서 설정", "홈페이지에 적용할 커서 이미지를 설정합니다.", "cf_cursor", $config);
setImageFile("SNS 카드 이미지 설정", "SNS등에서 링크 시 카드 이미지에 등록될 이미지를 설정합니다. 290px × 160px 크기로 설정하는 것이 좋습니다.", "cf_site_img", $config);
setListEditInput("접근 가능 IP", "입력된 IP의 컴퓨터만 접근할 수 있습니다. 123.123.+ 도 입력 가능.", "cf_possible_ip", $config, "\n");
setListEditInput("접근 차단 IP", "입력된 IP의 컴퓨터는 접근할 수 없음. 123.123.+ 도 입력 가능.", "cf_intercept_ip", $config, "\n");
setCheckbox("보안 연결(https) 강제 비활성화", "<b>※ 이 옵션을 사용하는 경우 제3자에 의해 홈페이지와 통신하는 내용이 감청될 가능성이 있습니다.</b><br>호스팅 환경이 정상적으로 https 를 지원하지 않는 경우에만 설정하세요.", "cf_use_http", "1", $config);
?>
</div>
</section>
<?php echo $frm_submit; ?>
<section id="anc_002">
<section id="anc_003">
<h2 class="h2_frm">게시판/회원 기본 설정</h2>
<?php echo $pg_anchor ?>
<div class="local_desc02 local_desc">
<p> 게시판 관리에서 개별적으로 설정 가능합니다.</p>
</div>
<div class="tbl_frm01 tbl_wrap">
<table>
<caption>게시판 기본 설정</caption>
<colgroup>
<col class="grid_4">
<col class="grid_10">
<col class="grid_4">
<col>
</colgroup>
<tbody>
<tr>
<th scope="row"><label for="cf_delay_sec">글쓰기 간격<strong class="sound_only">필수</strong></label></th>
<td><input type="text" name="cf_delay_sec" value="<?php echo $config['cf_delay_sec'] ?>" id="cf_delay_sec"
required class="required numeric frm_input" size="3"> 지난후 가능</td>
<th scope="row"><label for="cf_link_target">새창 링크</label></th>
<td>
<?php echo help('글내용중 자동 링크되는 타켓을 지정합니다.') ?>
<select name="cf_link_target" id="cf_link_target">
<option value="_blank" <?php echo get_selected($config['cf_link_target'], '_blank') ?>>_blank</option>
<option value="_self" <?php echo get_selected($config['cf_link_target'], '_self') ?>>_self</option>
<option value="_top" <?php echo get_selected($config['cf_link_target'], '_top') ?>>_top</option>
<option value="_new" <?php echo get_selected($config['cf_link_target'], '_new') ?>>_new</option>
</select>
</td>
</tr>
<tr>
<th scope="row"><label for="cf_filter">단어 필터링</label></th>
<td colspan="3">
<?php echo help('입력된 단어가 포함된 내용은 게시할 수 없습니다. 단어와 단어 사이는 ,로 구분합니다.') ?>
<textarea name="cf_filter" id="cf_filter" rows="7"><?php echo $config['cf_filter'] ?></textarea>
</td>
</tr>
<tr>
<th scope="row"><label for="cf_member_skin">회원 스킨<strong class="sound_only">필수</strong></label></th>
<td>
<?php echo get_skin_select('member', 'cf_member_skin', 'cf_member_skin', $config['cf_member_skin'], 'required'); ?>
</td>
<th scope="row"><label for="cf_register_level">회원가입시 권한</label></th>
<td><?php echo get_member_level_select('cf_register_level', 1, 9, $config['cf_register_level']) ?></td>
</tr>
<tr>
<th scope="row" id="th310"><label for="cf_leave_day">회원탈퇴후 삭제일</label></th>
<td colspan="3"><input type="text" name="cf_leave_day" value="<?php echo $config['cf_leave_day'] ?>"
id="cf_leave_day" class="frm_input" size="2"> 자동 삭제</td>
</tr>
<tr>
<th scope="row"><label for="cf_prohibit_id">아이디,닉네임 금지단어</label></th>
<td colspan="3">
<?php echo help('회원아이디, 닉네임으로 사용할 수 없는 단어를 정합니다. 쉼표 (,) 로 구분') ?>
<textarea name="cf_prohibit_id" id="cf_prohibit_id" rows="3"
style="height:100px;"><?php echo $config['cf_prohibit_id'] ?></textarea>
</td>
</tr>
</tbody>
</table>
<?php
$herfList = [
"_blank" => "_blank",
"_self" => "_self",
"_top" => "_top",
"_new" => "_new"
];
$memberSkinList = array_merge(['' => '선택'], getSkinList('member'));
$memberLevelList = getMemberLevels();
setOptionList("새 창 링크 시 동작 선택", "글 내용 중 자동으로 링크를 변환할 때 동작 방식을 결정합니다.", $herfList, "cf_link_target", '', $config, true);
setNumberInput("글쓰기 간격", "게시글 도배 방지를 위해 글 작성이 가능한 최소 시간을 설정합니다.", "cf_delay_sec", $config, "", "초 이후 가능");
setListEditInput("단어 필터링", "입력된 단어가 포함된 내용은 게시할 수 없습니다.", "cf_filter", $config, ",");
setOptionList("회원 스킨", "", $memberSkinList, "cf_member_skin", '', $config, true);
setOptionList("회원 기본 권한", "", $memberLevelList, "cf_register_level", '', $config, true);
setListEditInput("아이디 및 닉네임 금지 단어 설정", "회원아이디, 닉네임으로 사용할 수 없는 단어를 정합니다.", "cf_prohibit_id", $config, ",");
setNumberInput("회원정보 보존 기간", "회원이 탈퇴한 후 회원의 정보를 보존할 기간을 설정합니다. 기본값은 30일 입니다.", "cf_leave_day", $config, "", "일 이후 자동 삭제");
?>
</div>
</section>
<?php echo $frm_submit; ?>

View file

@ -23,7 +23,7 @@ $g5['title'] = "테마설정";
include_once "./admin.head.php";
?>
<script src="<?php echo G5_ADMIN_URL; ?>/js/theme.js"></script>
<div class="local_wr">
<div class="local_wr admin_theme">
<span class="btn_ov01"><span class="ov_txt">설치된 테마</span><span class="ov_num">
<?php echo number_format($total_count); ?></span></span>
</div>

View file

@ -198,8 +198,10 @@ switch ($day) {
});
});
</script>
</div>
<?php
}
include_once "./admin.tail.php";
?>
</div>
<?php
include_once "./admin.tail.php";

View file

@ -228,7 +228,7 @@ if (isset($wr_id) && $wr_id) {
// 전체목록보이기 사용이 "예" 또는 wr_id 값이 없다면 목록을 보임
//if ($board['bo_use_list_view'] || empty($wr_id))
if ($member['mb_level'] >= $board['bo_list_level'] && $board['bo_use_list_view'] || empty($wr_id)) {
if ($member['mb_level'] >= $board['bo_list_level'] && ($board['bo_use_list_view'] || empty($wr_id))) {
if ($board['bo_type'] == 'mmb')
include_once G5_BBS_PATH . "/list.mmb.php";
else

View file

@ -21,7 +21,7 @@ if (!($w == '' || $w == 'u' || $w == 'r')) {
}
if ($w == 'u' || $w == 'r') {
if ($write['wr_id']) {
if ($write['wr_id'] || $wr_parent == -1) {
// 가변 변수로 $wr_1 .. $wr_10 까지 만든다.
for ($i = 1; $i <= 10; $i++) {
$vvar = "wr_" . $i;

View file

@ -45,7 +45,7 @@ if ($w == 'c' && $_SESSION['ss_datetime'] >= (G5_SERVER_TIME - $config['cf_delay
set_session('ss_datetime', G5_SERVER_TIME);
$wr = get_write($write_table, $wr_id);
if (empty($wr['wr_id']))
if (empty($wr['wr_id']) && $wr_id != -1)
alert("글이 존재하지 않습니다.\\n글이 삭제되었거나 이동하였을 수 있습니다.");

View file

@ -79,7 +79,7 @@ $notice_array = explode(",", $board['bo_notice']);
if ($w == 'u' || $w == 'r') {
$wr = get_write($write_table, $wr_id);
if (!$wr['wr_id']) {
if (!$wr['wr_id'] && $wr_parent != -1) {
alert("글이 존재하지 않습니다.\\n글이 삭제되었거나 이동하였을 수 있습니다.");
}
}

View file

@ -4,6 +4,9 @@ class html_process
protected $latecss = [];
protected $css = [];
protected $js = [];
protected $beforeBuffer = "";
protected $afterBuffer = "";
protected $replacer = [];
private function updateLoginTable()
{
@ -188,9 +191,24 @@ class html_process
}*/
}
public function appendHtml($html)
{
$this->afterBuffer .= $html;
}
public function prependHtml($html)
{
$this->beforeBuffer .= $html;
}
public function addRegexReplace($pattern, $replace)
{
$this->replacer[] = [$pattern, $replace];
}
public function run()
{
global $config, $g5, $member;
global $config;
$this->updateLoginTable();
$this->cleanOldLoginRecords($config['cf_login_minutes']);
@ -203,6 +221,13 @@ class html_process
$buffer = $this->injectStyles($buffer, $stylesheet, $latestylesheet);
$buffer = $this->injectJavascript($buffer, $javascript);
foreach($this->replacer as $v) {
$buffer = preg_replace($v[0], $v[1], $buffer);
}
$buffer = preg_replace('#(</head>[^<]*<body[^>]*>)#', "$1{$this->beforeBuffer}", $buffer);
$buffer = preg_replace('#</(?:\s+)?body>#', "</body>" . $this->afterBuffer, $buffer);
if (class_exists("EventHandler")) {
EventHandler::triggerEvent("amber.renderhtml_before_print", $buffer);
}

View file

@ -2,13 +2,14 @@
/**
* THIS MODULE PROHIBITS DISTRIBUTION TO OTHERS WITHOUT AUTHOR'S PERMISSION.
* @class Setting
* @author arcturus (contact@sharlayan.net / https://info.drk.st/about)
* @author amberstone ( contact@drk.st / https://amberst.one )
* @brief gnuboard config extend class
* @version 1.1.0
* @version 1.1.2
* @license LGPL 2.1
*/
class Setting
{
public static $etc_max = 20;
public static $fonts;
public $idx;
public $html;
@ -88,15 +89,36 @@ class Setting
case "color2":
$this->addColor2Setting($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : []) : []);
break;
case "color3":
$this->addBackForeLine($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : []) : []);
break;
case "border":
$this->addBorderSetting($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : []) : []);
break;
case "border2":
$this->addBorder2Setting($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : []) : []);
break;
case "rect":
$this->addRectSetting($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : []) : []);
break;
case "radius":
$this->addRadiusSetting($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : []) : []);
break;
case "margin":
$this->addMarginSetting($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : []) : []);
break;
case "font":
$this->addFontSetting($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : "") : []);
break;
case "fontsize":
$this->addFontSizeSetting($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : "16") : []);
break;
case "number":
$this->addNumberSetting($set["desc"], array_key_exists("default", $set) ? $set["default"] : "0");
break;
case "background":
$this->addBackgroundSetting($set["desc"], array_key_exists("default", $set) ? (is_array($set["default"]) ? $set["default"] : []) : []);
break;
}
}
@ -112,7 +134,7 @@ class Setting
$set->cs_value = $row['cs_value'];
$set->cs_name = $row['cs_name'];
$set->cs_descript = $row['cs_descript'];
for ($i = 1; $i <= 20; $i++) {
for ($i = 1; $i <= self::$etc_max; $i++) {
$key = "cs_etc_{$i}";
$set->$key = $row[$key];
}
@ -134,7 +156,7 @@ class Setting
$set->cs_value = $row['cs_value'];
$set->cs_name = $row['cs_name'];
$set->cs_descript = $row['cs_descript'];
for ($i = 1; $i <= 20; $i++) {
for ($i = 1; $i <= self::$etc_max; $i++) {
$key = "cs_etc_{$i}";
$set->$key = $row[$key];
}
@ -152,14 +174,14 @@ class Setting
$this->cs_name = $data['cs_name'];
$this->cs_value = $data['cs_value'];
$this->cs_descript = $data['cs_descript'];
for ($i = 1; $i <= 20; $i++) {
for ($i = 1; $i <= self::$etc_max; $i++) {
$key = "cs_etc_{$i}";
$this->$key = $data[$key];
}
} else {
$this->cs_value = "";
$this->cs_descript = "";
for ($i = 1; $i <= 20; $i++) {
for ($i = 1; $i <= self::$etc_max; $i++) {
$key = "cs_etc_{$i}";
$this->$key = "";
}
@ -174,6 +196,12 @@ class Setting
$count += count(array_filter($this->settings, function ($setting) {
return $setting["type"] == "image";
})) ? 2 : 0;
$count += count(array_filter($this->settings, function ($setting) {
return $setting["type"] == "background";
})) ? 3 : 0;
$count += count(array_filter($this->settings, function ($setting) {
return $setting["type"] == "color3";
})) ? 2 : 0;
return "<tr><th rowspan=\"{$count}\" scope=\"row\"><em>{$this->idx}</em>{$this->title}<input type=\"text\" name=\"cs_name[{$this->idx}]\" value=\"{$this->cs_name}\" readonly size=\"15\" /></th>";
}
@ -191,6 +219,10 @@ class Setting
case "border":
$count += 2;
break;
case "border2":
case "color3":
$count += 3;
break;
default:
$count++;
break;
@ -253,10 +285,179 @@ class Setting
$this->is_value_added = true;
}
public function addBackgroundSetting($desc, $default)
{
if ($this->is_value_added)
return;
$idx = $this->getCurrentCount();
if ($idx == 0) {
$imgval = $this->cs_value;
$img = $this->cs_value ? "<img src=\"{$imgval}\" class=\"prev_thumb\"/>" : "이미지 미등록";
$color1 = $this->cs_etc_1;
$repeat = $this->cs_etc_2;
$align = $this->cs_etc_3;
$size = $this->cs_etc_4;
$position = $this->cs_etc_5 == "fixed" ? " selected" : "";
$repeats = ["", "", ""];
$aligns = ["", "", "", "", "", "", "", ""];
$sizes = ["", "", ""];
switch ($repeat) {
case "no-repeat":
$repeats[0] = " selected";
break;
case "repeat-x":
$repeats[1] = " selected";
break;
case "repeat-y":
$repeats[2] = " selected";
break;
}
switch ($align) {
case "left center":
$aligns[0] = " selected";
break;
case "left bottom":
$aligns[1] = " selected";
break;
case "center top":
$aligns[2] = " selected";
break;
case "center center":
$aligns[3] = " selected";
break;
case "center bottom":
$aligns[4] = " selected";
break;
case "right top":
$aligns[5] = " selected";
break;
case "right center":
$aligns[6] = " selected";
break;
case "right bottom":
$aligns[7] = " selected";
break;
}
switch ($size) {
case "contain":
$sizes[0] = " selected";
break;
case "cover":
$sizes[0] = " selected";
break;
case "100% 100%":
$sizes[0] = " selected";
break;
}
$this->settings[] = [
"type" => "background",
"html" => "
<td rowspan=\"4\" class=\"bo-right bo-left txt-center\">
{$img}
</td>
<td>
<div class=\"setter\">직접등록<input type=\"file\" name=\"cs_value_file[{$this->idx}]\" value=\"\" size=\"50\"></div>
</td></tr><tr>
<td>
<div class=\"setter\">외부경로<input type=\"text\" name=\"cs_value[{$this->idx}]\" value=\"{$imgval}\" size=\"50\"/></div>
</td></tr><tr>
<td>
<div class=\"setter\">색상<input type=\"text\" name=\"cs_etc_1[{$this->idx}]\" value=\"{$color1}\" class=\"neo_color\" size=\"30\" maxlength=\"255\" placeholder=\"#색상코드\" /></div>
</td></tr><tr>
<td>
<div class=\"setter\">배경반복
<select name=\"cs_etc_2[{$this->idx}]\">
<option value=\"\">반복</option>
<option value=\"no-repeat\"{$repeats[0]}>반복없음</option>
<option value=\"repeat-x\"{$repeats[1]}>가로반복</option>
<option value=\"repeat-y\"{$repeats[2]}>세로반복</option>
</select>
배경위치
<select name=\"cs_etc_3[{$this->idx}]\">
<option value=\"\">왼쪽 상단</option>
<option value=\"left center\"{$aligns[0]}>왼쪽 중단</option>
<option value=\"left bottom\"{$aligns[1]}>왼쪽 하단</option>
<option value=\"center top\"{$aligns[2]}>중간 상단</option>
<option value=\"center center\"{$aligns[3]}>중간 중단</option>
<option value=\"center bottom\"{$aligns[4]}>중간 하단</option>
<option value=\"right top\"{$aligns[5]}>오른쪽 상단</option>
<option value=\"right center\"{$aligns[6]}>오른쪽 중단</option>
<option value=\"right bottom\"{$aligns[7]}>오른쪽 하단</option>
</select>
</div>
<br />
<div class=\"setter\">
배경크기
<select name=\"cs_etc_4[{$this->idx}]\">
<option value=\"\">원본크기</option>
<option value=\"contain\"{$sizes[0]}>맞춤</option>
<option value=\"cover\"{$sizes[1]}>꽉참</option>
<option value=\"100% 100%\"{$sizes[2]}>늘이기</option>
</select>
고정
<select name=\"cs_etc_5[{$this->idx}]\">
<option value=\"\">스크롤</option>
<option value=\"fixed\"{$position}>고정</option>
</select>
</div>
</td>"
];
}
}
public function addFontSetting($desc, $default, $placeholder = "")
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= self::$etc_max) {
$key1 = "cs_etc_{$idx}";
$val = $this->$key1 ? $this->$key1 : (isset($default) ? $default : "");
$this->settings[] = [
"type" => "font",
"html" => "<td class=\"bo-right\">{$desc}</td><td><div class=\"setter\"><input type=\"text\" name=\"cs_etc_{$idx}[{$this->idx}]\" value=\"{$val}\" size=\"100\" placeholder=\"{$placeholder}\" /></div></td></tr>"
];
}
}
public function addFontSizeSetting($desc, $default)
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= self::$etc_max) {
$key1 = "cs_etc_{$idx}";
$val = $this->$key1 ? $this->$key1 : (isset($default) ? $default : 16);
$this->settings[] = [
"type" => "font",
"html" => "<td class=\"bo-right\">{$desc}</td><td><div class=\"setter\"><input type=\"number\" name=\"cs_etc_{$idx}[{$this->idx}]\" value=\"{$val}\" style=\"width: 60px\" min=\"9\" max=\"72\" /></div></td></tr>"
];
}
}
public function addNumberSetting($desc, $default)
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= self::$etc_max) {
$key1 = "cs_etc_{$idx}";
$val = $this->$key1 ? $this->$key1 : (isset($default) ? $default : 0);
$this->settings[] = [
"type" => "number",
"html" => "<td class=\"bo-right\">{$desc}</td><td><div class=\"setter\"><input type=\"number\" name=\"cs_etc_{$idx}[{$this->idx}]\" value=\"{$val}\" style=\"width: 60px\" min=\"-5000\" max=\"5000\" /></div></td></tr>"
];
}
}
public function addRectSetting($desc, $default)
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= 20) {
if ($idx <= self::$etc_max) {
$key1 = "cs_etc_{$idx}";
$values = explode("||", $this->$key1);
@ -277,10 +478,10 @@ class Setting
"html" => "<td class=\"bo-right\">{$desc}</td>
<td>
<div class=\"setter\">
<div style=\"display:flex;gap:8px;border:1px solid #F4F4F2;align-items:center;padding:4px 8px;width:120px;justify-content:end;\">X<input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[1]}\"/>px</div>
<div style=\"display:flex;gap:8px;border:1px solid #F4F4F2;align-items:center;padding:4px 8px;width:120px;justify-content:end;\">Y<input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[2]}\"/>px</div>
<div style=\"display:flex;gap:8px;border:1px solid #F4F4F2;align-items:center;padding:4px 8px;width:120px;justify-content:end;\">너비<input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[3]}\"/>px</div>
<div style=\"display:flex;gap:8px;border:1px solid #F4F4F2;align-items:center;padding:4px 8px;width:120px;justify-content:end;\">높이<input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[4]}\"/>px</div>
<div class=\"css-setting-multi\"><span class=\"css-left-desc\">X</span><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[1]}\"/>px</div>
<div class=\"css-setting-multi\"><span class=\"css-left-desc\">Y</span><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[2]}\"/>px</div>
<div class=\"css-setting-multi\"><span class=\"css-left-desc\">너비</span><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[3]}\"/>px</div>
<div class=\"css-setting-multi\"><span class=\"css-left-desc\">높이</span><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[4]}\"/>px</div>
</div>
</td>
</tr>"
@ -292,7 +493,7 @@ class Setting
public function addRadiusSetting($desc, $default)
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= 20) {
if ($idx <= self::$etc_max) {
$key1 = "cs_etc_{$idx}";
$values = explode("||", $this->$key1);
@ -313,10 +514,46 @@ class Setting
"html" => "<td class=\"bo-right\">{$desc}</td>
<td>
<div class=\"setter\">
<div style=\"display:flex;gap:8px;border:1px solid #F4F4F2;align-items:center;padding:4px 8px;width:120px;justify-content:end;\"><div style=\"width: 16px; height: 16px; background: #866; box-sizing: border-box; border-radius: 8px 0 0 0;\"></div><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[1]}\"/>px</div>
<div style=\"display:flex;gap:8px;border:1px solid #F4F4F2;align-items:center;padding:4px 8px;width:120px;justify-content:end;\"><div style=\"width: 16px; height: 16px; background: #866; box-sizing: border-box; border-radius: 0 8px 0 0;\"></div><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[2]}\"/>px</div>
<div style=\"display:flex;gap:8px;border:1px solid #F4F4F2;align-items:center;padding:4px 8px;width:120px;justify-content:end;\"><div style=\"width: 16px; height: 16px; background: #866; box-sizing: border-box; border-radius: 0 0 8px 0;\"></div><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[3]}\"/>px</div>
<div style=\"display:flex;gap:8px;border:1px solid #F4F4F2;align-items:center;padding:4px 8px;width:120px;justify-content:end;\"><div style=\"width: 16px; height: 16px; background: #866; box-sizing: border-box; border-radius: 0 0 0 8px;\"></div><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[4]}\"/>px</div>
<div class=\"css-setting-multi\"><div class=\"css-setting-radius\" style=\"border-radius: 8px 0 0 0;\"></div><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[1]}\"/>px</div>
<div class=\"css-setting-multi\"><div class=\"css-setting-radius\" style=\"border-radius: 0 8px 0 0;\"></div><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[2]}\"/>px</div>
<div class=\"css-setting-multi\"><div class=\"css-setting-radius\" style=\"border-radius: 0 0 8px 0;\"></div><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[3]}\"/>px</div>
<div class=\"css-setting-multi\"><div class=\"css-setting-radius\" style=\"border-radius: 0 0 0 8px;\"></div><input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[4]}\"/>px</div>
</div>
</td>
</tr>"
];
}
// error
}
public function addMarginSetting($desc, $default)
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= self::$etc_max) {
$key1 = "cs_etc_{$idx}";
$values = explode("||", $this->$key1);
if (empty($default)) {
$default = [0, 0, 0, 0];
}
if (count($values) < 6) {
$values = array_merge([""], $default, [""]);
}
foreach ($values as &$val) {
$val = intval($val);
}
$this->settings[] = [
"type" => "margin",
"html" => "<td class=\"bo-right\">{$desc}</td>
<td>
<div class=\"setter\">
<div class=\"css-setting-multi\">상<input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[1]}\"/>px</div>
<div class=\"css-setting-multi\">하<input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[2]}\"/>px</div>
<div class=\"css-setting-multi\">좌<input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[3]}\"/>px</div>
<div class=\"css-setting-multi\">우<input type=\"number\" id=\"cs_etc_{$idx}_1_{$this->cs_name}\" min=\"-9999\" max=\"9999\" size=\"20\" name=\"cs_etc_{$idx}[{$this->idx}][]\" value=\"{$values[4]}\"/>px</div>
</div>
</td>
</tr>"
@ -328,7 +565,7 @@ class Setting
public function addColorSetting($desc, $default)
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= 19) {
if ($idx <= self::$etc_max - 1) {
$idx2 = $idx + 1;
$key1 = "cs_etc_{$idx}";
$key2 = "cs_etc_{$idx2}";
@ -349,7 +586,7 @@ class Setting
public function addColor2Setting($desc, $default)
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= 20) {
if ($idx <= self::$etc_max) {
$key1 = "cs_etc_{$idx}";
if (empty($default)) {
if ($this->$key1 === "")
@ -381,10 +618,16 @@ class Setting
"outset" => "외부"
];
if ($idx <= 19) {
if ($idx <= self::$etc_max - 2) {
$idx2 = $idx + 1;
$key1 = "cs_etc_{$idx}";
$key2 = "cs_etc_{$idx2}";
if (is_array($default) && isset($default[0]) && isset($default[1])) {
if (empty($this->$key1))
$this->$key1 = array_key_exists($default[0], $options) ? $default[0] : "";
if (empty($this->$key2) && $this->$key2 !== 0)
$this->$key2 = intval($default[1]);
}
$options_html = "";
foreach ($options as $key => $val) {
$k = trim($key);
@ -398,11 +641,118 @@ class Setting
}
}
public function addBorder2Setting($desc, $default)
{
$idx = $this->getCurrentCount() + 1;
$options = [
" " => "사용 안 함",
"dotted" => "점선",
"dashed" => "대시",
"solid" => "직선",
"double" => "이중선",
"groove" => "내부 경사",
"ridge" => "외부 경사",
"inset" => "내부",
"outset" => "외부"
];
if ($idx <= self::$etc_max - 3) {
$idx2 = $idx + 1;
$idx3 = $idx + 2;
$key1 = "cs_etc_{$idx}";
$key2 = "cs_etc_{$idx2}";
$key3 = "cs_etc_{$idx3}";
if (is_array($default) && isset($default[0]) && isset($default[1])) {
if (empty($this->$key1))
$this->$key1 = array_key_exists($default[0], $options) ? $default[0] : "";
if (empty($this->$key2) && $this->$key2 !== 0)
$this->$key2 = intval($default[1]);
}
if (empty($this->$key3) && $this->$key3 !== 0) {
if ($this->$key3 === "" || !isset($this->$key3))
$this->$key3 = intval($default[2]);
}
$values = explode("||", $this->$key3);
$options_html = "";
foreach ($options as $key => $val) {
$k = trim($key);
$s = $this->$key1 == $k ? " selected" : "";
$options_html .= "<option value=\"{$k}\"{$s}>{$val}</option>";
}
$checked_top = in_array("top", $values) ? " checked" : "";
$checked_bottom = in_array("bottom", $values) ? " checked" : "";
$checked_left = in_array("left", $values) ? " checked" : "";
$checked_right = in_array("right", $values) ? " checked" : "";
$this->settings[] = [
"type" => "border",
"html" => "<td class=\"bo-right\">{$desc}</td>
<td>
<div class=\"setter\">
<select name=\"cs_etc_{$idx}[{$this->idx}]\">{$options_html}</select>
두께<input type=\"number\" name=\"cs_etc_{$idx2}[{$this->idx}]\" value=\"{$this->$key2}\" placeholder=\"0\" title=\"두께\" style=\"width:45px;\"/>
</div>
<div class=\"setter\" style=\"margin-top: 8px\">
<input type=\"checkbox\" name=\"cs_etc_{$idx3}[{$this->idx}][]\" id=\"cs_etc_{$idx3}_1_{$this->cs_name}\" style=\"max-width: 24px\" value=\"top\" {$checked_top}/>
<input type=\"checkbox\" name=\"cs_etc_{$idx3}[{$this->idx}][]\" id=\"cs_etc_{$idx3}_2_{$this->cs_name}\" style=\"max-width: 24px\" value=\"bottom\" {$checked_bottom}/>
<input type=\"checkbox\" name=\"cs_etc_{$idx3}[{$this->idx}][]\" id=\"cs_etc_{$idx3}_3_{$this->cs_name}\" style=\"max-width: 24px\" value=\"left\" {$checked_left}/>
<input type=\"checkbox\" name=\"cs_etc_{$idx3}[{$this->idx}][]\" id=\"cs_etc_{$idx3}_4_{$this->cs_name}\" style=\"max-width: 24px\" value=\"right\" {$checked_right}/>
</div>
</td>
</tr>"
];
}
}
public function addBackForeLine($desc, $default)
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= self::$etc_max - 3) {
$key1 = "cs_etc_{$idx}";
$idx2 = $idx + 1;
$key2 = "cs_etc_{$idx2}";
$idx3 = $idx + 2;
$key3 = "cs_etc_{$idx3}";
if (is_array($default)) {
$cnt = count($default);
switch($cnt) {
case 3:
{
$this->$key3 = $default[2];
}
case 2:
{
$this->$key2 = $default[1];
}
case 1:
{
$this->$key1 = $default[0];
}
}
}
$this->settings[] = [
"type" => "color3",
"html" => "<td class=\"bo-right\">배경</td><td><div class=\"setter\">색상 <input type=\"text\" name=\"cs_etc_{$idx}[{$this->idx}]\" value=\"{$this->$key1}\" class=\"neo_color\" size=\"30\" maxlength=\"255\" placeholder=\"#색상코드\" /></div></td></tr>" .
"<tr><td class=\"bo-right\">폰트</td><td><div class=\"setter\">색상 <input type=\"text\" name=\"cs_etc_{$idx2}[{$this->idx}]\" value=\"{$this->$key2}\" class=\"neo_color\" size=\"30\" maxlength=\"255\" placeholder=\"#색상코드\" /></div></td></tr>" .
"<tr><td class=\"bo-right\">라인</td><td><div class=\"setter\">색상 <input type=\"text\" name=\"cs_etc_{$idx3}[{$this->idx}]\" value=\"{$this->$key3}\" class=\"neo_color\" size=\"20\" maxlength=\"255\" placeholder=\"#색상코드\" /></div></td></tr>"
];
}
}
public function addSelectSetting($desc, $default, $values)
{
$idx = $this->getCurrentCount() + 1;
if ($idx <= 19) {
if ($idx <= self::$etc_max - 1) {
$key1 = "cs_etc_{$idx}";
$options_html = "";
foreach ($values as $key => $val) {

View file

@ -1,8 +1,12 @@
<?php
/**
* @suppress PHP0419
* @suppress PHP6405
*/
/*******************************************************************************
** 공통 변수, 상수, 코드
*******************************************************************************/
error_reporting(E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_PARSE | E_USER_ERROR);
error_reporting(E_CORE_ERROR | E_COMPILE_ERROR | E_ERROR | E_PARSE | E_USER_ERROR);
// 보안설정이나 프레임이 달라도 쿠키가 통하도록 설정
header('P3P: CP="ALL CURa ADMa DEVa TAIa OUR BUS IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC OTC"');
@ -416,10 +420,10 @@ if (file_exists($dbconfig_file)) {
<link rel="stylesheet" href="install/install.css">
</head>
<body>
<div id="ins_bar">
<span id="bar_img">AVOCADO EDITION</span>
<span id="bar_txt">Message</span>
</div>
<?php
$RIGHT_MESSAGE = "Message";
include G5_PATH . "/install/install_header.php";
?>
<h1>아보카도 에디션을 먼저 설치해주십시오.</h1>
<div class="ins_inner">
<p>다음 파일을 찾을 없습니다.</p>
@ -458,10 +462,10 @@ if (!defined('G5_IS_ADMIN')) {
<link rel="stylesheet" href="<?= G5_URL ?>/install/install.css">
</head>
<body>
<div id="ins_bar">
<span id="bar_img">AVOCADO EDITION</span>
<span id="bar_txt">Message</span>
</div>
<?php
$RIGHT_MESSAGE = "Message";
include G5_PATH . "/install/install_header.php";
?>
<h1>아보카도 에디션 설정을 완료해주십시오.</h1>
<br />
<div class="ins_inner">
@ -487,12 +491,15 @@ if (!defined('G5_IS_ADMIN')) {
@ini_set("session.use_trans_sid", 0); // PHPSESSID를 자동으로 넘기지 않음
@ini_set("url_rewriter.tags", ""); // 링크에 PHPSESSID가 따라다니는것을 무력화함 (해뜰녘님께서 알려주셨습니다.)
session_save_path(G5_SESSION_PATH);
if (isset($SESSION_CACHE_LIMITER))
if (USE_REDIS && extension_loaded('redis')) {
ini_set('session.save_path', 'tcp://localhost:6379');
} else {
session_save_path(G5_SESSION_PATH);
if (isset($SESSION_CACHE_LIMITER))
@session_cache_limiter($SESSION_CACHE_LIMITER);
else
else
@session_cache_limiter("no-cache, must-revalidate");
}
ini_set("session.cache_expire", 180); // 세션 캐쉬 보관시간 (분)
ini_set("session.gc_maxlifetime", 10800); // session data의 garbage collection 존재 기간을 지정 (초)

View file

@ -2,12 +2,21 @@
/**
* @suppress PHP0419
*/
// if you want use redis-session, enable it (change to true)
define('USE_REDIS', false);
if (USE_REDIS) {
ini_set('session.save_handler', 'redis');
} else {
ini_set('session.save_handler', 'files');
}
/********************
상수 선언
********************/
define('G5_VERSION', '아보카도 에디션 : Amber');
define('G5_GNUBOARD_VER', '2.3.3');
define('G5_GNUBOARD_VER', '2.3.4');
define('G5_AMBER', true);
define('_GNUBOARD_', true);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,55 @@
@charset "utf-8";
@font-face {
font-family: 'SCDream';
font-weight: 900;
src: url(./fonts/SCDream9.otf);
}
@font-face {
font-family: 'SCDream';
font-weight: 800;
src: url(./fonts/SCDream8.otf);
}
@font-face {
font-family: 'SCDream';
font-weight: 700;
src: url(./fonts/SCDream7.otf);
}
@font-face {
font-family: 'SCDream';
font-weight: 600;
src: url(./fonts/SCDream6.otf);
}
@font-face {
font-family: 'SCDream';
font-weight: 500;
src: url(./fonts/SCDream5.otf);
}
@font-face {
font-family: 'SCDream';
font-weight: 400;
src: url(./fonts/SCDream4.otf);
}
@font-face {
font-family: 'SCDream';
font-weight: 300;
src: url(./fonts/SCDream3.otf);
}
@font-face {
font-family: 'SCDream';
font-weight: 200;
src: url(./fonts/SCDream2.otf);
}
@font-face {
font-family: 'SCDream';
font-weight: 100;
src: url(./fonts/SCDream1.otf);
}

View file

@ -9,7 +9,7 @@ Character::resetSearchCount();
if ($is_admin) {
if (!sql_table_exists($g5["article_table"])) {
sql_query("CREATE TABLE IF NOT EXISTS `avo_article` (
sql_query("CREATE TABLE IF NOT EXISTS `{$g5["article_table"]}` (
`ar_id` INT(11) NOT NULL AUTO_INCREMENT,
`ar_theme` VARCHAR(255) NOT NULL DEFAULT '',
`ar_code` VARCHAR(255) NOT NULL DEFAULT '',
@ -26,7 +26,7 @@ if ($is_admin) {
}
if (!sql_table_exists($g5["article_default_table"])) {
sql_query("CREATE TABLE IF NOT EXISTS `avo_article_default` (
sql_query("CREATE TABLE IF NOT EXISTS `{$g5["article_default_table"]}` (
`ad_id` INT(11) NOT NULL AUTO_INCREMENT ,
`ad_use_thumb` INT(11) NOT NULL DEFAULT '0',
`ad_use_head` INT(11) NOT NULL DEFAULT '0',
@ -56,7 +56,7 @@ if ($is_admin) {
}
if (!sql_table_exists($g5["value_table"])) {
sql_query("CREATE TABLE IF NOT EXISTS `avo_article_value` (
sql_query("CREATE TABLE IF NOT EXISTS `{$g5["value_table"]}` (
`av_id` INT(11) NOT NULL AUTO_INCREMENT ,
`ch_id` INT(11) NOT NULL DEFAULT '0',
`ar_theme` VARCHAR(255) NOT NULL DEFAULT '',

View file

@ -87,8 +87,10 @@ $html_class .= $_COOKIE['header_close'] == 'close' ? " close-header" : "";
include_once __DIR__ . "/_extra_font.php";
if (defined('G5_IS_ADMIN')) {
echo get_embed_file("css", G5_ADMIN_PATH . '/css/admin.css') . PHP_EOL;
echo get_embed_file("css", G5_ADMIN_PATH . '/css/admin.layout.css') . PHP_EOL;
// echo get_embed_file("css", G5_ADMIN_PATH . '/css/admin.css') . PHP_EOL;
// echo get_embed_file("css", G5_ADMIN_PATH . '/css/admin.layout.css') . PHP_EOL;
// echo get_embed_file("css", G5_ADMIN_PATH . '/css/admin.amber.lib.css') . PHP_EOL;
echo get_embed_file("css", G5_ADMIN_PATH . '/css/default.css') . PHP_EOL;
echo get_embed_file("css", G5_ADMIN_PATH . '/css/amberstone.cp.css') . PHP_EOL;
} else {
if (defined('G5_THEME_PATH') && file_exists(G5_THEME_PATH . "/css/default.css")) {

View file

@ -1,13 +1,13 @@
<?php
include_once "../config.php";
$theme_1 = "#BEBE8E";
$theme_2 = "#7F7F5F";
$theme_3 = "#7C7C4C";
$theme_1 = "#ecc6c6";
$theme_2 = "#e8b0ae";
$theme_3 = "#d6817e";
$theme_4 = "#b0c4de";
$theme_5 = "#727F99";
$theme_6 = "#7488B2";
$theme_5 = "#88a9db";
$theme_6 = "#779bdb";
$title = G5_VERSION . " 라이센스 확인 1/3";

View file

@ -1,11 +1,23 @@
@charset "utf-8";
/* SIR 지운아빠 */
:root {
--bg-color: #181926;
--text-color: #CAD3F5;
--accent-color: #ffbf00;
--border-color: #6E738D;
--button-bg-color: #ffbf00;
--button-bg-hover-color: #CAD3F5;
--button-text-color: #000;
--header-bg-color: #24273A;
}
/* 공통 */
body {
margin: 0;
padding: 0;
background: url('img/pat01.png') #edf0f4;
background: var(--bg-color);
color: var(--text-color);
font-size: 14px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
font-size: 0.75em;
font-family: dotum, helvetica
}
@ -25,8 +37,8 @@ label {
#ins_bar {
margin: 0 0 50px;
padding: 20px 30px;
background: #383838;
color: #a1a4a7;
background: var(--header-bg-color);
color: var(--text-color);
font-family: tahoma, helvetica;
font-size: 1.500em;
zoom: 1
@ -56,9 +68,9 @@ h1 {
.ins_inner {
margin: 0 30px 50px;
padding: 20px 30px;
border-right: 1px solid #dde4e9;
border-bottom: 1px solid #dde4e9;
background: #fff
border: 1px solid var(--border-color);
border-radius: 4px;
background: transparent
}
.ins_inner ul {
@ -76,7 +88,8 @@ h1 {
}
.ins_inner p strong {
color: red
font-size: 1.5em;
color: var(--accent-color)
}
.ins_inner .inner_btn {
@ -88,11 +101,32 @@ h1 {
.ins_inner .inner_btn input {
display: inline-block;
padding: 10px 20px;
background: #BEBE8E;
color: #fff;
background: var(--button-bg-color);
color: var(--button-text-color);
border-radius: 4px;
text-decoration: none
}
.ins_inner .inner_btn a:hover,
.ins_inner .inner_btn input:hover,
.ins_inner .inner_btn button:hover {
background: var(--button-bg-hover-color);
}
.ins_inner pre {
font-size: 12px;
margin: 10px 0;
padding: 10px;
overflow: auto
}
.ins_inner pre::before {
content: "[AvocadoAmber ~] ";
display: inline;
height: 0;
overflow: hidden
}
.ins_inner .inner_btn input {
border: 0;
cursor: pointer
@ -114,13 +148,12 @@ h1 {
.ins_frm th,
.ins_frm td {
padding: 5px 3px;
border-top: 1px solid #dde4e9;
border-bottom: 1px solid #dde4e9
border: 1px solid var(--border-color);
}
.ins_frm th {
width: 25%;
background: #f2f5f9
background: var(--header-bg-color)
}
.ins_frm td span {
@ -130,9 +163,18 @@ h1 {
letter-spacing: -0.1em
}
.ins_frm input {
background: transparent;
padding: 4px 8px;
border: 1px solid var(--border-color);
color: var(--text-color);
font-size: 1.25em;
}
.ins_ta {
padding: 5px 0;
border: 1px solid #dde4e9;
border: 1px solid var(--border-color);
border-radius: 4px;
text-align: center
}
@ -141,11 +183,13 @@ h1 {
padding: 0;
width: 99%;
height: 250px;
color: var(--text-color);
background: transparent
}
.ins_license {
background: #f2f5f9
background: var(--bg-color);
color: var(--text-color)
}
#ins_ft {
@ -168,8 +212,8 @@ h1 {
/* extra */
pre {
padding: 4px;
background: #0d1117;
color: #f0f6fc;
background: var(--bg-color);
color: var(--text-color);
font-size: 14px;
font-family: monospace;
user-select: all;

View file

@ -17,12 +17,9 @@ if (!$title)
</head>
<body>
<div id="ins_bar">
<span id="bar_img">AVOCADO EDITION</span>
<span id="bar_txt">INSTALLATION</span>
</div>
<?php
include "./install_header.php";
?>
<?php
// 파일이 존재한다면 설치할 수 없다.
$dbconfig_file = $data_path . '/' . G5_DBCONFIG_FILE;
@ -70,10 +67,11 @@ if (!$title)
?>
<div class="ins_inner">
<p>
<b><?php echo G5_DATA_DIR ?> 디렉토리의 퍼미션을 705로 변경하여 주십시오.</b><br>
<pre>#> chmod 705 <?php echo G5_DATA_DIR ?></pre>
<?php echo G5_DATA_DIR ?> 디렉토리의 퍼미션을 705로 변경하여 주십시오.<br>
아래 내용을 클릭하면 명령어가 전체 선택됩니다.<br>
<pre>chmod 705 <?php echo G5_DATA_DIR ?></pre>
또는<br>
<pre>#> chmod uo+rx <?php echo G5_DATA_DIR ?></pre><br>
<pre>chmod uo+rx <?php echo G5_DATA_DIR ?></pre><br>
명령 실행후 브라우저를 새로고침 하십시오.
</p>
</div>
@ -81,15 +79,20 @@ if (!$title)
$write_data_dir = false;
}
} else {
// 생성 시도 후 권한이 없으면 안내
if (!file_exists($data_path)) {
@mkdir($data_path, G5_DIR_PERMISSION);
}
if (!(is_readable($data_path) && is_writeable($data_path) && is_executable($data_path))) {
?>
<div class="ins_inner">
<p>
<b><?php echo G5_DATA_DIR ?> 디렉토리의 퍼미션을 707로 변경하여 주십시오.</b><br>
<pre>#> chmod 707 <?php echo G5_DATA_DIR ?></pre>
<?php echo G5_DATA_DIR ?> 디렉토리의 퍼미션을 707로 변경하여 주십시오.<br>
아래 내용을 클릭하면 명령어가 전체 선택됩니다.<br>
<pre>chmod 707 <?php echo G5_DATA_DIR ?></pre>
또는<br>
<pre>#> chmod uo+rwx <?php echo G5_DATA_DIR ?></pre><br>
<pre>chmod uo+rwx <?php echo G5_DATA_DIR ?></pre><br>
명령 실행후 브라우저를 새로고침 하십시오.
</p>
</div>
@ -101,10 +104,11 @@ if (!$title)
?>
<div class="ins_inner">
<p>
<b><?php echo G5_CSS_DIR ?> 디렉토리의 퍼미션을 707로 변경하여 주십시오.</b><br>
<pre>#> chmod 707 <?php echo G5_CSS_DIR ?></pre>
<?php echo G5_CSS_DIR ?> 디렉토리의 퍼미션을 707로 변경하여 주십시오.<br>
아래 내용을 클릭하면 명령어가 전체 선택됩니다.<br>
<pre>chmod 707 <?php echo G5_CSS_DIR ?></pre>
또는<br>
<pre>#> chmod uo+rwx <?php echo G5_CSS_DIR ?></pre><br>
<pre>chmod uo+rwx <?php echo G5_CSS_DIR ?></pre><br>
명령 실행후 브라우저를 새로고침 하십시오.
</p>
</div>

View file

@ -1,7 +1,7 @@
<?php
?><div id="ins_ft">
<strong>AVOCADO EDITION</strong>
<strong>AVOCADO EDITION: AMBER</strong>
<p>GPL! OPEN SOURCE GNUBOARD</p>
</div>
</body>

View file

@ -102,7 +102,7 @@ if (!isset($_POST['agree']) || $_POST['agree'] != '동의함') {
</table>
<p>
<strong class="st_strong">주의! 이미 <?php echo G5_VERSION ?>이 존재한다면 DB 자료가 망실되므로 주의하십시오.</strong><br>
<strong class="st_strong">이미 <?php echo G5_VERSION ?>를 설치한 경우, 재설치 시 기존 데이터베이스를 잃어버리므로 주의해 주시기 바랍니다!</strong><br>
주의사항을 이해했으며, 아보카도 에디션 설치를 계속 진행하시려면 다음을 누르십시오.
</p>

View file

@ -32,7 +32,6 @@ $admin_id = $_POST['admin_id'];
$admin_pass = $_POST['admin_pass'];
$admin_name = $_POST['admin_name'];
$admin_email = $_POST['admin_email'];
$absolute_password = $_POST['absolute_password'];
$table_url = $_POST['table_url'];
$dblink = sql_connect($mysql_host, $mysql_user, $mysql_pass, $mysql_db);
@ -273,6 +272,7 @@ unset($row);
// 디렉토리 생성
$dir_arr = array(
$data_path . '/css',
$data_path . '/cache',
$data_path . '/editor',
$data_path . '/file',
@ -366,16 +366,9 @@ EOD;
//-------------------------------------------------------------------------------------------------
// CSS 설정 파일 생성
$css_data_path = $g5_path['path'] . "/css";
$css_data_url = $g5_path['url'] . "/css";
$css_data_path = $data_path . "/css";
@mkdir($css_data_path, G5_DIR_PERMISSION);
@chmod($css_data_path, G5_DIR_PERMISSION);
$file = '../' . G5_CSS_DIR . '/_design.config.css';
$file_path = $css_data_path . '/_design.config.css';
@unlink($file_path);
$file = $css_data_path . '/_design.config.css';
$f = @fopen($file, 'a');
?>
<li style="display:none;">
@ -403,6 +396,8 @@ EOD;
sql_query(" set time_zone = '" . G5_TIMEZONE . "'");
}
$g5['css_table'] = $table_prefix . 'css_config';
ob_start();
include "../adm/design_form_css.php";
$css = ob_get_contents();

View file

@ -0,0 +1,2 @@
<?php
?><div id="ins_bar"><span id="bar_img">AVOCADO EDITION: AMBER</span><span id="bar_txt"><?php echo $RIGHT_MESSAGE ? $RIGHT_MESSAGE : "INSTALLATION" ?></span></div>

View file

@ -4,7 +4,7 @@ if (!defined('_GNUBOARD_'))
function editor_html($id, $content, $is_dhtml_editor = true)
{
global $g5, $config, $w, $board, $write;
global $g5, $config, $w, $board, $write, $is_admin;
static $js = true;
if (
@ -71,7 +71,10 @@ function editor_html($id, $content, $is_dhtml_editor = true)
}
$smarteditor_class = $is_dhtml_editor ? "smarteditor2" : "";
$html .= "\n<textarea id=\"$id\" name=\"$id\" class=\"$smarteditor_class\" maxlength=\"65536\" style=\"width:100%;height:300px\">$content</textarea>";
if (!isset($is_admin)) {
$maxlength = "maxlength=\"65536\" ";
}
$html .= "\n<textarea id=\"$id\" name=\"$id\" class=\"$smarteditor_class\" {$maxlength}style=\"width:100%;height:300px\">$content</textarea>";
$html .= "\n<span class=\"sound_only\">웹 에디터 끝</span>";
return $html;
}

View file

@ -95,10 +95,7 @@ nhn.husky.SE2M_AttachQuickPhoto = jindo.$Class({
*/
_getPhotoTag: function (htPhotoInfo) {
// id와 class는 썸네일과 연관이 많습니다. 수정시 썸네일 영역도 Test
var sTag = '<img src="{=sOriginalImageURL}" title="{=sName}" >';
if (htPhotoInfo.bNewLine) {
sTag += '<br style="clear:both;">';
}
var sTag = '<br><img src="{=sOriginalImageURL}" title="{=sName}" ><br>';
sTag = jindo.$Template(sTag).process(htPhotoInfo);
return sTag;

View file

@ -10,16 +10,11 @@ add_stylesheet('<link rel="stylesheet" href="' . $member_skin_url . '/style.admi
<div class="inner">
<h1>
<em>
<strong><?= $config['cf_title'] ?> 관리자</strong> 로그인
<?= $config['cf_title'] ?>
</em>
<span>
AVOCADO EDITION Ver.<?= G5_GNUBOARD_VER ?>
Ver.<?= G5_GNUBOARD_VER ?>
</span>
<sup>
관리자 비번을 잊을 , DB 접속을 통해 직접 변경 하여야 합니다.<br />
최대한 비밀번호를 잊지 않도록 조심해 주시길 바랍니다.<br />
DB 관리툴은 호스팅 업체에 문의해 주시길 바랍니다.
</sup>
</h1>
</div>
</div>

View file

@ -1,265 +1,109 @@
@charset "utf-8";
@import url(//fonts.googleapis.com/earlyaccess/notosanskr.css);
@import url(../../../adm/css/default.css);
@font-face {
font-family: 'icon';
src: url('../../../css/fonts/icomoon.eot?y5isk6');
src: url('../../../css/fonts/icomoon.eot?y5isk6#iefix') format('embedded-opentype'),
url('../../../css/fonts/icomoon.ttf?y5isk6') format('truetype'),
url('../../../css/fonts/icomoon.woff?y5isk6') format('woff'),
url('../../../css/fonts/icomoon.svg?y5isk6#icomoon') format('svg');
font-weight: normal;
font-style: normal;
/* override */
html, body {
display: block;
padding: 0;
margin: 0;
}
html,
body {
position: relative;
height: 100%;
background: #fff;
background: var(--white);
}
#login_page_box {
position: relative;
width: 100%;
height: 100%;
}
#login_page_box:before {
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
height: 50%;
box-sizing: border-box;
border-top: 8px solid #ecc6c6;
background: url('./img/bak_admin_login_top_pattern.png');
z-index: 0;
}
#login_page_box:after {
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
height: 50%;
background: rgba(0, 0, 0, 0);
background: -moz-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 65%, rgba(0, 0, 0, 0.5) 100%);
background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(0, 0, 0, 0)), color-stop(65%, rgba(0, 0, 0, 0)), color-stop(100%, rgba(0, 0, 0, 0.5)));
background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 65%, rgba(0, 0, 0, 0.5) 100%);
background: -o-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 65%, rgba(0, 0, 0, 0.5) 100%);
background: -ms-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 65%, rgba(0, 0, 0, 0.5) 100%);
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 65%, rgba(0, 0, 0, 0.5) 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#000000', endColorstr='#000000', GradientType=0);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#login_title {
display: block;
position: relative;
height: 50%;
padding-bottom: 130px;
box-sizing: border-box;
z-index: 3;
}
#login_title .inner {
position: relative;
width: 100%;
height: 100%;
}
#login_title h1 {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
font-family: 'Noto Sans KR', sans-serif;
font-size: 35px;
font-weight: 600;
}
#login_title em {
font-style: normal;
color: #ecc6c6;
text-align: center;
line-height: 1.5em;
}
#login_title em strong {
color: #fff;
}
#login_title span {
display: block;
font-size: 16px;
font-weight: 400;
color: #999;
text-align: center;
}
#login_title sup {
display: block;
position: relative;
font-size: 13px;
font-weight: 300;
text-align: center;
padding: 0;
margin-top: 20px;
color: #777;
left: 0;
top: 0;
width: 100%;
height: 50vh;
display: flex;
box-sizing: border-box;
padding: 20px;
justify-content: start;
align-items: center;
flex-direction: column;
background: linear-gradient(to top, var(--theme-gray-900) 0%, var(--theme-gray-800) 50%, var(--theme-gray-800) 100%);
}
#mb_login {
position: absolute;
top: 50%;
left: 50%;
width: 500px;
height: 260px;
border-top: 5px solid #ecc6c6;
transform: translateX(-50%) translateY(-50%);
background: #fff;
-webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.49);
-moz-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.49);
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.49);
z-index: 5;
}
#mb_login:before {
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: -20px;
background: #fff;
z-index: 0;
}
#mb_login .inner {
position: relative;
padding: 30px;
z-index: 1;
}
#mb_login fieldset.input {
display: block;
position: relative;
margin-bottom: 5px;
margin-right: 130px;
}
#mb_login fieldset.input input {
display: block;
width: 100%;
padding: 40px;
border-radius: 16px;
background: var(--white);
min-width: 360px;
box-sizing: border-box;
background: #fff !important;
color: #3a3a3b;
height: 45px;
padding: 0 15px 0 45px;
font-size: 15px;
font-family: 'Noto Sans KR', sans-serif;
outline: none;
border: 1px solid #eaeaea;
filter: drop-shadow(0 0 15px #0002);
}
#mb_login fieldset.input input:focus {
border: 2px solid #ecc6c6;
}
#mb_login fieldset.input label {
display: block;
position: absolute;
top: 0;
left: 0;
width: 45px;
height: 45px;
line-height: 45px;
overflow: hidden;
text-indent: -999px;
}
#mb_login fieldset.input label:before {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
text-indent: 0;
text-align: center;
font-family: 'icon';
font-size: 16px;
color: #ccc;
}
#mb_login fieldset.input input:focus+label:before {
color: #ecc6c6;
}
#mb_login fieldset.input label.login_id:before {
content: "\e976";
}
#mb_login fieldset.input label.login_pw:before {
content: "\e98e";
}
#mb_login fieldset.input input:-webkit-autofill {
transition: background-color 50000s ease-in-out 0s;
-webkit-box-shadow: 0 0 0 30px white inset;
-webkit-text-fill-color: #3a3a3b !important;
}
#mb_login fieldset.check {
#mb_login fieldset {
display: block;
position: relative;
padding: 5px;
background: #f6f6f6;
border: 1px solid #ebebeb;
color: #3a3a3a;
margin: 5px 130px 5px 0;
font-size: 11px;
padding-top: 1.5em;
margin-bottom: 1em;
}
#mb_login fieldset.check label {
cursor: pointer;
}
#mb_login fieldset.button {
#mb_login fieldset label{
display: block;
position: absolute;
top: 30px;
right: 30px;
width: 126px;
height: 128px;
left: 0;
top: 0em;
color: var(--theme-gray-500);
}
#mb_login fieldset.button .btn_submit {
display: block;
#mb_login fieldset input:not([type=checkbox]) {
width: 100%;
height: 100%;
background: #ecc6c6;
font-family: 'Noto Sans KR', sans-serif;
font-size: 18px;
border: none;
cursor: pointer;
color: #fff;
display: block;
box-sizing: border-box;
padding: 4px 8px;
line-height: 2em;
height: auto;
border-radius: 4px;
}
#mb_login fieldset button.btn_submit {
display: block;
box-sizing: border-box;
border: unset;
width: 100%;
height: auto;
line-height: 3em;
border-radius: 4px;
}
#copyright {
padding-top: 30px;
font-size: 12px;
color: #aaa;
color: var(--theme-gray-500);
text-align: center;
font-size: 11px;
border-top: 1px solid var(--theme-gray-100);
margin-top: 1em;
padding-top: 1em;
}
#login_title .inner h1 {
color: var(--white);
display: flex;
flex-direction: column;
text-align: center;
line-height: 1.25em;
}
#login_title .inner h1 span {
font-size: 14px;
}
#login_title .inner h1 sup {
font-size: 16px;
line-height: 1.25em;
}

View file

@ -41,3 +41,5 @@ AvocadoEdition Light 의 구조를 바탕으로 GNUBoard 기능과 함께 재수
- 압축을 풀어 호스팅의 `public` 또는 `www`, `public_html` 폴더에 업로드합니다.
(또는 ssh 로 접속하여 직접 업로드하고 압축을 해제해도 됩니다.)
이후 호스팅 주소로 접속하여 설치 프로그램을 실행합니다.
### ※ 일부 관리자 페이지 관련 수정은 호환되지 않을 수 있습니다.