Merge branch 'rhymix:master' into master

This commit is contained in:
Lastorder 2026-01-08 20:28:49 -08:00 committed by GitHub
commit 2efe733d5f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 67 additions and 22 deletions

View file

@ -10,9 +10,9 @@ if(!defined('__XE__'))
* @brief admin log * @brief admin log
*/ */
$logged_info = Context::get('logged_info'); $logged_info = Context::get('logged_info');
if(Context::get('is_logged') && $logged_info->is_admin == 'Y' && stripos(Context::get('act'), 'admin') !== false && $called_position == 'before_module_proc') if ($called_position === 'before_module_proc' && $logged_info->is_admin === 'Y' && stripos(Context::get('act') ?? '', 'admin') !== false)
{ {
$oAdminloggingController = getController('adminlogging'); $oAdminloggingController = adminloggingController::getInstance();
$oAdminloggingController->insertLog($this->module, $this->act); $oAdminloggingController->insertLog($this->module, $this->act);
} }
/* End of file adminlogging.php */ /* End of file adminlogging.php */

View file

@ -185,7 +185,7 @@ class BaseObject
{ {
$type = $this->get('message_type'); $type = $this->get('message_type');
$typeList = array('error' => 1, 'info' => 1, 'update' => 1); $typeList = array('error' => 1, 'info' => 1, 'update' => 1);
if(!isset($typeList[$type])) if (!isset($type) || !isset($typeList[$type]))
{ {
$type = $this->getError() ? 'error' : 'info'; $type = $this->getError() ? 'error' : 'info';
} }

View file

@ -127,9 +127,18 @@ class DB
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => false, \PDO::ATTR_EMULATE_PREPARES => false,
\PDO::ATTR_STATEMENT_CLASS => array('\Rhymix\Framework\Helpers\DBStmtHelper'), \PDO::ATTR_STATEMENT_CLASS => array('\Rhymix\Framework\Helpers\DBStmtHelper'),
\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false,
); );
// Use unbuffered queries to reduce memory usage.
if (\PHP_VERSION_ID >= 80400)
{
$options[\PDO\MySQL::ATTR_USE_BUFFERED_QUERY] = false;
}
else
{
$options[\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY] = false;
}
// Preload the statement helper class. // Preload the statement helper class.
class_exists('\Rhymix\Framework\Helpers\DBStmtHelper'); class_exists('\Rhymix\Framework\Helpers\DBStmtHelper');

View file

@ -179,14 +179,18 @@ class TemplateParser_v2
*/ */
protected function _addContextSwitches(string $content): string protected function _addContextSwitches(string $content): string
{ {
$context_index = random_int(12000, 99000);
// Inline styles. // Inline styles.
$content = preg_replace_callback('#(?<=\s)(style=")([^"]*?)"#i', function($match) { $content = preg_replace_callback('#(?<=\s)(style=")([^"]*?)"#i', function($match) {
return $match[1] . '<?php $this->config->context = \'CSS\'; ?>' . $match[2] . '<?php $this->config->context = \'HTML\'; ?>"'; return $match[1] . '<?php $this->config->context = \'CSS\'; ?>' . $match[2] . '<?php $this->config->context = \'HTML\'; ?>"';
}, $content); }, $content);
// Inline scripts. // Inline scripts.
$content = preg_replace_callback('#(?<=\s)(href="javascript:|pattern="|on[a-z]+=")([^"]*?)"#i', function($match) { $content = preg_replace_callback('#(?<=\s)(href="javascript:|pattern="|on[a-z]+=")([^"]*?)"#i', function($match) use(&$context_index) {
return $match[1] . '<?php $this->config->context = \'JS\'; ?>' . $match[2] . '<?php $this->config->context = \'HTML\'; ?>"'; $context_index++;
return $match[1] . '<?php $this->config->context = \'JS\'; /* !CTX' . $context_index . '! */?>' .
$match[2] . '<?php $this->config->context = \'HTML\'; /* !CTX' . $context_index . '! */?>"';
}, $content); }, $content);
// <style> tags. // <style> tags.
@ -202,14 +206,15 @@ class TemplateParser_v2
}, $content); }, $content);
// <script> tags that aren't links. // <script> tags that aren't links.
$content = preg_replace_callback('#(<script\b([^>]*)|</script)#i', function($match) { $content = preg_replace_callback('#(<script\b([^>]*)|</script)#i', function($match) use(&$context_index) {
if (substr($match[1], 1, 1) === '/') if (substr($match[1], 1, 1) === '/')
{ {
return '<?php $this->config->context = \'HTML\'; ?>' . $match[1]; return '<?php $this->config->context = \'HTML\'; /* !CTX' . $context_index . '! */?>' . $match[1];
} }
elseif (!str_contains($match[2] ?? '', 'src="')) elseif (!str_contains($match[2] ?? '', 'src="'))
{ {
return $match[1] . '<?php $this->config->context = \'JS\'; ?>'; $context_index++;
return $match[1] . '<?php $this->config->context = \'JS\'; /* !CTX' . $context_index . '! */?>';
} }
else else
{ {
@ -217,6 +222,18 @@ class TemplateParser_v2
} }
}, $content); }, $content);
// Remove nested context switches.
if ($context_index > 0)
{
$content = preg_replace_callback('#(<\?php \$this->config->context = \'JS\'; /\* !CTX([0-9]+)! \*/\?>)(.*?)(<\?php \$this->config->context = \'HTML\'; /\* !CTX\2! \*/\?>)#s', function($match) {
return preg_replace('#/\* !CTX\d+! \*/#', '', $match[1]) .
preg_replace('#<\?php \$this->config->context = \'[A-Z]+\'; (?:/\* !CTX[0-9]+! \*/)?\?>#', '', $match[3]) .
preg_replace('#/\* !CTX\d+! \*/#', '', $match[4]);
}, $content);
$content = preg_replace('#(<\?php \$this->config->context = \'[A-Z]+\'; )/\* !CTX[0-9]+! \*/(\?>)#', '$1$2', $content);
}
return $content; return $content;
} }

View file

@ -9,6 +9,8 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<form id="fo_list" action="./" method="post"> <form id="fo_list" action="./" method="post">
<table id="commentListTable" class="x_table x_table-striped x_table-hover dsTg"> <table id="commentListTable" class="x_table x_table-striped x_table-hover dsTg">
<caption> <caption>
<a href="{getUrl('search_target', $search_target, 'search_keyword', $search_keyword)}" cond="!empty($search_target) && $search_target !== 'is_secret' && !empty($search_keyword)" class="active">{$lang->cmd_search}({number_format($total_count)})</a>
<i>|</i>
<a href="{getUrl('','module','admin','act','dispCommentAdminList','Y')}" class="active"|cond="$search_keyword == ''">{$lang->all}<block cond="$search_keyword == ''">({number_format($total_count)})</block></a> <a href="{getUrl('','module','admin','act','dispCommentAdminList','Y')}" class="active"|cond="$search_keyword == ''">{$lang->all}<block cond="$search_keyword == ''">({number_format($total_count)})</block></a>
<i>|</i> <i>|</i>
<a href="{getUrl('search_target','is_secret','search_keyword','N')}" class="active"|cond="$search_target == 'is_secret' && $search_keyword == 'N'">{$secret_name_list['N']}<block cond="$search_target == 'is_secret' && $search_keyword == 'N'">({number_format($total_count)})</block></a> <a href="{getUrl('search_target','is_secret','search_keyword','N')}" class="active"|cond="$search_target == 'is_secret' && $search_keyword == 'N'">{$secret_name_list['N']}<block cond="$search_target == 'is_secret' && $search_keyword == 'N'">({number_format($total_count)})</block></a>

View file

@ -894,7 +894,7 @@ class DocumentController extends Document
if (!$manual_inserted) if (!$manual_inserted)
{ {
$ev_output = $extra_item->validate($value); $ev_output = $extra_item->validate($value);
if ($ev_output && !$output->toBool()) if ($ev_output && !$ev_output->toBool())
{ {
$oDB->rollback(); $oDB->rollback();
return $ev_output; return $ev_output;

View file

@ -11,6 +11,8 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<input type="hidden" name="page" value="{$page}" /> <input type="hidden" name="page" value="{$page}" />
<table id="documentListTable" class="x_table x_table-striped x_table-hover dsTg"> <table id="documentListTable" class="x_table x_table-striped x_table-hover dsTg">
<caption> <caption>
<a href="{getUrl('search_target', $search_target, 'search_keyword', $search_keyword)}" cond="!empty($search_target) && $search_target !== 'is_secret' && !empty($search_keyword)" class="active">{$lang->cmd_search}({number_format($total_count)})</a>
<i>|</i>
<a href="{getUrl('', 'module', 'admin', 'act', 'dispDocumentAdminList')}" class="active"|cond="$search_keyword == ''">{$lang->all}<block cond="$search_keyword == ''">({number_format($total_count)})</block></a> <a href="{getUrl('', 'module', 'admin', 'act', 'dispDocumentAdminList')}" class="active"|cond="$search_keyword == ''">{$lang->all}<block cond="$search_keyword == ''">({number_format($total_count)})</block></a>
<i>|</i> <i>|</i>
<a href="{getUrl('search_target', 'is_secret', 'search_keyword', 'N')}" class="active"|cond="$search_target == 'is_secret' && $search_keyword == 'N'">{$status_name_list['PUBLIC']}<block cond="$search_target == 'is_secret' && $search_keyword == 'N'">({number_format($total_count)})</block></a> <a href="{getUrl('search_target', 'is_secret', 'search_keyword', 'N')}" class="active"|cond="$search_target == 'is_secret' && $search_keyword == 'N'">{$status_name_list['PUBLIC']}<block cond="$search_target == 'is_secret' && $search_keyword == 'N'">({number_format($total_count)})</block></a>

View file

@ -10,8 +10,8 @@
<caption>Total : {number_format($total_count)}, Page {number_format($page)}/{number_format($total_page)}</caption> <caption>Total : {number_format($total_count)}, Page {number_format($page)}/{number_format($total_page)}</caption>
<thead> <thead>
<tr> <tr>
<th class="title">{$lang->date}</th>
<th class="title">{$lang->title}</th> <th class="title">{$lang->title}</th>
<th class="title">{$lang->date}</th>
<th class="title" style="width:60px">{$lang->cmd_select}</th> <th class="title" style="width:60px">{$lang->cmd_select}</th>
<th class="title" style="width:60px">{$lang->cmd_delete}</th> <th class="title" style="width:60px">{$lang->cmd_delete}</th>
</tr> </tr>
@ -19,14 +19,18 @@
<tbody> <tbody>
<!--@foreach($document_list as $no => $val)--> <!--@foreach($document_list as $no => $val)-->
<tr> <tr>
<td>{$val->getRegdate("Y-m-d H:i:s")}</td>
<td> <td>
<a href="#" class="toggle_content">{$val->getTitle()}</a> <a href="#" class="toggle_content" data-document-srl="{$val->document_srl}">{$val->getTitle()}</a>
<div id="saved_document_{$val->document_srl}" class="saved_content" style="display:none;margin:20px -120px 0 0">{$val->getContent(false)}</div>
</td> </td>
<td>{$val->getRegdate("Y-m-d H:i:s")}</td>
<td><a href="#" class="btn btn_select_temp_saved" data-document-srl="{$val->document_srl}" data-document-type="{$val->getDocumentType()}">{$lang->cmd_select}</a></td> <td><a href="#" class="btn btn_select_temp_saved" data-document-srl="{$val->document_srl}" data-document-type="{$val->getDocumentType()}">{$lang->cmd_select}</a></td>
<td><a href="#" class="btn btn_delete_temp_saved" data-document-srl="{$val->document_srl}">{$lang->cmd_delete}</a></td> <td><a href="#" class="btn btn_delete_temp_saved" data-document-srl="{$val->document_srl}">{$lang->cmd_delete}</a></td>
</tr> </tr>
<tr id="saved_document_{$val->document_srl}" class="saved_content" style="display:none">
<td colspan="4">
{$val->getSummary(200)}
</td>
</tr>
<!--@end--> <!--@end-->
</tbody> </tbody>
</table> </table>
@ -49,7 +53,8 @@
$(function() { $(function() {
$('.toggle_content').on('click', function(event) { $('.toggle_content').on('click', function(event) {
event.preventDefault(); event.preventDefault();
$(this).next('.saved_content').toggle(); var document_srl = $(this).data('documentSrl');
$('#saved_document_' + document_srl).toggle();
setFixedPopupSize(); setFixedPopupSize();
}); });
$('.btn_select_temp_saved').on('click', function(event) { $('.btn_select_temp_saved').on('click', function(event) {

View file

@ -189,6 +189,8 @@ class FileAdminView extends File
Context::set('total_page', $output->total_page); Context::set('total_page', $output->total_page);
Context::set('page', $output->page); Context::set('page', $output->page);
Context::set('page_navigation', $output->page_navigation); Context::set('page_navigation', $output->page_navigation);
Context::set('isvalid', $args->isvalid);
// Set a template // Set a template
$security = new Security(); $security = new Security();
$security->encodeHTML('file_list..'); $security->encodeHTML('file_list..');

View file

@ -12,7 +12,9 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<input type="hidden" name="module" value="file" /> <input type="hidden" name="module" value="file" />
<table id="fileListTable" class="x_table x_table-striped x_table-hover"> <table id="fileListTable" class="x_table x_table-striped x_table-hover">
<caption> <caption>
<a href="{getUrl('', 'module', 'admin', 'act', 'dispFileAdminList')}" class="active"|cond="!$isvalid">{$lang->all}<block cond="!$isvalid">({number_format($total_count)})</block></a> <a href="{getUrl('search_target', $search_target, 'search_keyword', $search_keyword)}" cond="!empty($search_target) && !empty($search_keyword)" class="active">{$lang->cmd_search}({number_format($total_count)})</a>
<i>|</i>
<a href="{getUrl('', 'module', 'admin', 'act', 'dispFileAdminList')}" class="active"|cond="empty($isvalid) && empty($search_target) && empty($search_keyword)">{$lang->all}<block cond="empty($isvalid) && empty($search_target) && empty($search_keyword)">({number_format($total_count)})</block></a>
<i>|</i> <i>|</i>
<a href="{getUrl('isvalid', 'Y')}" class="active"|cond="$isvalid == 'Y'">{$lang->is_valid}<block cond="$isvalid == 'Y'">({number_format($total_count)})</block></a> <a href="{getUrl('isvalid', 'Y')}" class="active"|cond="$isvalid == 'Y'">{$lang->is_valid}<block cond="$isvalid == 'Y'">({number_format($total_count)})</block></a>
<i>|</i> <i>|</i>

View file

@ -341,7 +341,8 @@ $lang->set_manage_id = 'Separated by line breaks.';
$lang->count_manage_id = 'There are <span class="_deniedIDCount">%s</span> prohibited ID.'; $lang->count_manage_id = 'There are <span class="_deniedIDCount">%s</span> prohibited ID.';
$lang->count_manage_nick_name = 'There are <span class="_deniedNickNameCount">%s</span> prohibited nick name.'; $lang->count_manage_nick_name = 'There are <span class="_deniedNickNameCount">%s</span> prohibited nick name.';
$lang->user_list = 'Member List'; $lang->user_list = 'Member List';
$lang->cmd_show_all_member = 'All Member'; $lang->cmd_show_all_member = 'All Members';
$lang->cmd_show_searched_member = 'Searched Members';
$lang->cmd_show_super_admin_member = 'Super Admin'; $lang->cmd_show_super_admin_member = 'Super Admin';
$lang->cmd_show_site_admin_member = 'Site Admin'; $lang->cmd_show_site_admin_member = 'Site Admin';
$lang->approval = 'Approval'; $lang->approval = 'Approval';

View file

@ -346,6 +346,7 @@ $lang->count_manage_id = '<span class="_deniedIDCount">%s</span>개의 금지
$lang->count_manage_nick_name = '<span class="_deniedNickNameCount">%s</span>개의 금지 닉네임이 있습니다.'; $lang->count_manage_nick_name = '<span class="_deniedNickNameCount">%s</span>개의 금지 닉네임이 있습니다.';
$lang->user_list = '회원 목록'; $lang->user_list = '회원 목록';
$lang->cmd_show_all_member = '모든 회원'; $lang->cmd_show_all_member = '모든 회원';
$lang->cmd_show_searched_member = '검색된 회원';
$lang->cmd_show_super_admin_member = '최고 관리자'; $lang->cmd_show_super_admin_member = '최고 관리자';
$lang->cmd_show_site_admin_member = '사이트 관리자'; $lang->cmd_show_site_admin_member = '사이트 관리자';
$lang->approval = '승인'; $lang->approval = '승인';

View file

@ -14,7 +14,7 @@
<form action="" method="post"> <form action="" method="post">
<table id="memberList" class="x_table x_table-striped x_table-hover dsTg"> <table id="memberList" class="x_table x_table-striped x_table-hover dsTg">
<caption> <caption>
<a href="{getUrl('filter_type', '', 'page', '')}" class="active"|cond="!$filter_type">{$lang->cmd_show_all_member}<block cond="!$filter_type">({$total_count})</block></a> <a href="{getUrl('filter_type', '', 'page', '')}" class="active"|cond="empty($filter_type)">{empty($search_keyword) ? $lang->cmd_show_all_member : $lang->cmd_show_searched_member}<block cond="empty($filter_type)">({$total_count})</block></a>
<i>|</i> <i>|</i>
<a href="{getUrl('filter_type', 'admin', 'page', '')}" class="active"|cond="$filter_type=='admin'">{$lang->cmd_show_super_admin_member}<block cond="$filter_type=='admin'">({$total_count})</block></a> <a href="{getUrl('filter_type', 'admin', 'page', '')}" class="active"|cond="$filter_type=='admin'">{$lang->cmd_show_super_admin_member}<block cond="$filter_type=='admin'">({$total_count})</block></a>
<i>|</i> <i>|</i>

View file

@ -337,8 +337,12 @@ class SpamfilterController extends Spamfilter
if (count($target_actions)) if (count($target_actions))
{ {
$captcha_class = 'Rhymix\\Modules\\Spamfilter\\Captcha\\' . $config->captcha->type; $captcha_class = 'Rhymix\\Modules\\Spamfilter\\Captcha\\' . $config->captcha->type;
$captcha_class::init($config->captcha); if (!class_exists($captcha_class))
{
return;
}
$captcha_class::init($config->captcha);
if (strncasecmp('proc', $obj->act, 4) === 0) if (strncasecmp('proc', $obj->act, 4) === 0)
{ {
$captcha_class::check(); $captcha_class::check();

View file

@ -218,7 +218,7 @@ class SpamfilterModel extends Spamfilter
{ {
$config = ModuleModel::getModuleConfig('spamfilter'); $config = ModuleModel::getModuleConfig('spamfilter');
$user = Context::get('logged_info'); $user = Context::get('logged_info');
if (!isset($config) || empty($config->captcha) || empty($config->captcha->type) || empty($config->captcha->site_key) || empty($config->captcha->secret_key)) if (!isset($config) || empty($config->captcha) || empty($config->captcha->type) || $config->captcha->type === 'none' || empty($config->captcha->site_key) || empty($config->captcha->secret_key))
{ {
return false; return false;
} }
@ -253,7 +253,7 @@ class SpamfilterModel extends Spamfilter
public static function getCaptcha($target_action = null) public static function getCaptcha($target_action = null)
{ {
$config = ModuleModel::getModuleConfig('spamfilter'); $config = ModuleModel::getModuleConfig('spamfilter');
if (!isset($config) || empty($config->captcha) || empty($config->captcha->type) || empty($config->captcha->site_key) || empty($config->captcha->secret_key)) if (!isset($config) || empty($config->captcha) || empty($config->captcha->type) || $config->captcha->type === 'none' || empty($config->captcha->site_key) || empty($config->captcha->secret_key))
{ {
return null; return null;
} }
@ -285,7 +285,7 @@ class SpamfilterModel extends Spamfilter
public static function checkCaptchaResponse(?string $response = null): void public static function checkCaptchaResponse(?string $response = null): void
{ {
$config = ModuleModel::getModuleConfig('spamfilter'); $config = ModuleModel::getModuleConfig('spamfilter');
if (!isset($config) || empty($config->captcha) || empty($config->captcha->type) || empty($config->captcha->site_key) || empty($config->captcha->secret_key)) if (!isset($config) || empty($config->captcha) || empty($config->captcha->type) || $config->captcha->type === 'none' || empty($config->captcha->site_key) || empty($config->captcha->secret_key))
{ {
throw new Exception('msg_recaptcha_not_configured'); throw new Exception('msg_recaptcha_not_configured');
} }