This commit is contained in:
Amberstone 2025-11-20 20:20:53 +09:00
parent 867d098ce3
commit 565b889cd4
Signed by: amber
GPG key ID: 094B0E55F98D8BF1
4 changed files with 357 additions and 4 deletions

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

@ -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,12 @@ $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="color: #ff6b6b; font-weight: bold; margin-left: 20px;">
<span class="material-icons" style="vertical-align: middle; font-size: 18px;">warning</span>
업데이트 필요: <?php echo count($boards_need_update) ?>
</span>
<?php } ?>
</div>
<form name="fsearch" id="fsearch" class="local_sch01 local_sch" method="get">
@ -106,12 +116,13 @@ $colspan = 11;
<th scope="col" style="width:100px;"><?php echo subject_sort_link('bo_table') ?>TABLE</a></th>
<th scope="col" style="width:150px;"><?php echo subject_sort_link('bo_skin', '', 'desc') ?>스킨</a></th>
<th scope="col"><?php echo subject_sort_link('bo_subject') ?>제목</a></th>
<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: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:90px;">관리</th>
</tr>
</thead>
<tbody>
@ -120,6 +131,15 @@ $colspan = 11;
$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>';
// 마이그레이션 필요 여부 체크
$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);
?>
@ -147,6 +167,13 @@ $colspan = 11;
<input type="text" name="bo_subject[<?php echo $i ?>]" value="<?php echo get_text($row['bo_subject']) ?>"
id="bo_subject_<?php echo $i ?>" required class="required frm_input bo_subject full_input" size="25">
</td>
<td>
<?php if ($need_migration) { ?>
<span style="color: #ff6b6b; font-weight: bold;">업데이트 필요</span>
<?php } else { ?>
<span style="color: #51cf66;"><?php echo htmlspecialchars($row['bo_version']); ?></span>
<?php } ?>
</td>
<td>
<?php echo get_member_level_select('bo_list_level[' . $i . ']', 1, 10, $row['bo_list_level']) ?>
</td>
@ -165,12 +192,16 @@ $colspan = 11;
<td>
<?php echo $one_update ?>
<?php echo $one_copy ?>
<?php if ($need_migration) { ?>
<br><a href="#" class="btn_migrate" data-bo-table="<?php echo $row['bo_table'] ?>"
style="color: #ff6b6b;">업데이트</a>
<?php } ?>
</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 +217,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" style="background-color: #ff6b6b;">
<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 +245,12 @@ $colspan = 11;
}
}
if (document.pressed == "선택마이그레이션") {
if (!confirm("선택한 게시판을 마이그레이션 하시겠습니까?")) {
return false;
}
}
return true;
}
@ -216,6 +259,37 @@ $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) {
alert(response.message + '\n업데이트된 컬럼: ' + response.updated + '개');
location.reload();
} else {
alert('오류: ' + response.message);
}
},
error: function () {
alert('마이그레이션 중 오류가 발생했습니다.');
}
});
});
});
</script>

View file

@ -1,8 +1,66 @@
<?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 ($_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']}";
}
}
$alert_message = "마이그레이션 완료\n\n";
$alert_message .= "성공: {$success_count}\n";
$alert_message .= "실패: {$fail_count}\n\n";
$alert_message .= implode("\n", $messages);
alert($alert_message, './board_list.php?' . $qstr);
}
if (!count($_POST['chk'])) {
alert($_POST['act_button'] . " 하실 항목을 하나 이상 체크하세요.");
}

View file

@ -0,0 +1,219 @@
<?php
if (!defined('_GNUBOARD_'))
exit;
// 현재 마이그레이션 버전
define('BOARD_MIGRATION_VERSION', '2.0.0');
// 표준 게시판 테이블 구조 정의
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 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 = [];
foreach ($standard as $column => $definition) {
if (!isset($current[$column])) {
$missing_columns[$column] = $definition;
}
}
return $missing_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' => '테이블이 존재하지 않습니다.'];
}
// 누락된 컬럼 확인
$missing_columns = compare_table_structure($write_table);
if (empty($missing_columns)) {
// 버전 업데이트만 수행
$sql = "UPDATE {$g5['board_table']} SET bo_version = '" . BOARD_MIGRATION_VERSION . "' WHERE bo_table = '{$bo_table}'";
sql_query($sql);
return ['success' => true, 'message' => '이미 최신 버전입니다.', 'updated' => 0];
}
// 컬럼 추가
$updated = 0;
foreach ($missing_columns as $column => $definition) {
$sql = "ALTER TABLE `{$write_table}` ADD `{$column}` {$definition}";
if (sql_query($sql)) {
$updated++;
}
}
// 버전 업데이트
$sql = "UPDATE {$g5['board_table']} SET bo_version = '" . BOARD_MIGRATION_VERSION . "' WHERE bo_table = '{$bo_table}'";
sql_query($sql);
return ['success' => true, 'message' => '마이그레이션이 완료되었습니다.', 'updated' => $updated];
}
// 모든 게시판 체크
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'];
$missing = compare_table_structure($write_table);
$boards_need_update[] = [
'bo_table' => $row['bo_table'],
'current_version' => $row['bo_version'],
'missing_columns' => count($missing)
];
}
}
return $boards_need_update;
}