mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-01-04 01:01:41 +09:00
Merge branch 'rhymix:master' into master
This commit is contained in:
commit
d327bb1926
43 changed files with 588 additions and 221 deletions
|
|
@ -163,7 +163,7 @@ class Context
|
|||
{
|
||||
// Create a singleton instance and initialize static properties.
|
||||
self::$_instance = new Context();
|
||||
self::$_oFrontEndFileHandler = self::$_instance->oFrontEndFileHandler = new FrontEndFileHandler();
|
||||
self::$_oFrontEndFileHandler = self::$_instance->oFrontEndFileHandler = FrontEndFileHandler::getInstance();
|
||||
self::$_user_vars = self::$_user_vars ?: new stdClass;
|
||||
}
|
||||
return self::$_instance;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ class DisplayHandler extends Handler
|
|||
{
|
||||
public static $response_size = 0;
|
||||
public static $debug_printed = 0;
|
||||
public $content_size = 0;
|
||||
public $handler = NULL;
|
||||
|
||||
/**
|
||||
|
|
@ -140,12 +139,15 @@ class DisplayHandler extends Handler
|
|||
$buff = ltrim($buff, "\n\r\t\v\x00\x20\u{FEFF}");
|
||||
|
||||
// call a trigger after display
|
||||
self::$response_size = $this->content_size = strlen($output);
|
||||
ModuleHandler::triggerCall('display', 'after', $output);
|
||||
|
||||
// Measure the response size.
|
||||
self::$response_size = strlen((string)$output);
|
||||
|
||||
// Output buffered content only if the current page is HTML.
|
||||
if ($handler instanceof HTMLDisplayHandler)
|
||||
{
|
||||
self::$response_size += strlen($buff);
|
||||
echo $buff;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,13 +53,38 @@ class FrontEndFileHandler extends Handler
|
|||
*/
|
||||
public $jsBodyMapIndex = array();
|
||||
|
||||
/**
|
||||
* Logging
|
||||
*/
|
||||
protected $_log_enabled = false;
|
||||
protected $_log_entries = [];
|
||||
|
||||
/**
|
||||
* Singleton
|
||||
*/
|
||||
protected static $_instance = null;
|
||||
|
||||
/**
|
||||
* Get singleton instance
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function getInstance(): self
|
||||
{
|
||||
if (self::$_instance === null)
|
||||
{
|
||||
self::$_instance = new self();
|
||||
}
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check SSL
|
||||
*
|
||||
* @return bool If using ssl returns true, otherwise returns false.
|
||||
* @deprecated
|
||||
*/
|
||||
public function isSsl()
|
||||
public static function isSsl()
|
||||
{
|
||||
return \RX_SSL;
|
||||
}
|
||||
|
|
@ -92,6 +117,10 @@ class FrontEndFileHandler extends Handler
|
|||
{
|
||||
$args = array($args);
|
||||
}
|
||||
if ($this->_log_enabled)
|
||||
{
|
||||
$this->_log_entries[] = $args;
|
||||
}
|
||||
|
||||
// Replace obsolete paths with current paths.
|
||||
$args[0] = preg_replace(array_keys(HTMLDisplayHandler::$replacements), array_values(HTMLDisplayHandler::$replacements), $args[0]);
|
||||
|
|
@ -252,6 +281,26 @@ class FrontEndFileHandler extends Handler
|
|||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start logging.
|
||||
*/
|
||||
public function startLog()
|
||||
{
|
||||
$this->_log_enabled = true;
|
||||
$this->_log_entries = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* End logging and return the log entries.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function endLog(): array
|
||||
{
|
||||
$this->_log_enabled = false;
|
||||
return $this->_log_entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process CSS and JS file
|
||||
*
|
||||
|
|
|
|||
|
|
@ -848,15 +848,10 @@ class ModuleHandler extends Handler
|
|||
$seo_title = config('seo.subpage_title') ?: '$SITE_TITLE - $SUBPAGE_TITLE';
|
||||
}
|
||||
$seo_title = Context::replaceUserLang($seo_title);
|
||||
$subpage_title = $module_info->browser_title;
|
||||
if (in_array($module_info->module, ['member']))
|
||||
{
|
||||
$subpage_title = '';
|
||||
}
|
||||
Context::setBrowserTitle($seo_title, array(
|
||||
'site_title' => Context::getSiteTitle(),
|
||||
'site_subtitle' => Context::getSiteSubtitle(),
|
||||
'subpage_title' => $subpage_title,
|
||||
'subpage_title' => $module_info->browser_title,
|
||||
'page' => Context::get('page') ?: 1,
|
||||
));
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"license": "GPL-2.0-or-later",
|
||||
"type": "project",
|
||||
"authors": [
|
||||
{ "name": "Rhymix Developers and Contributors", "email": "devops@rhymix.org" },
|
||||
{ "name": "Poesis Inc. and Contributors", "email": "devops@rhymix.org" },
|
||||
{ "name": "NAVER", "email": "developers@xpressengine.com" }
|
||||
],
|
||||
"config": {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
/**
|
||||
* RX_VERSION is the version number of the Rhymix CMS.
|
||||
*/
|
||||
define('RX_VERSION', '2.1.21');
|
||||
define('RX_VERSION', '2.1.23');
|
||||
|
||||
/**
|
||||
* RX_MICROTIME is the startup time of the current script, in microseconds since the Unix epoch.
|
||||
|
|
|
|||
|
|
@ -945,6 +945,31 @@ class Template
|
|||
return count($args) ? in_array((string)$validator_id, $args, true) : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current visitor is using a mobile device for v2.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _v2_isMobile(): bool
|
||||
{
|
||||
return UA::isMobile() && (config('mobile.tablets') || !UA::isTablet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Contextual escape function for v2.
|
||||
*
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
protected function _v2_escape($str): string
|
||||
{
|
||||
switch ($this->config->context)
|
||||
{
|
||||
case 'JS': return escape_js(strval($str));
|
||||
default: return escape(strval($str));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lang shortcut for v2.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -450,14 +450,28 @@ class VariableBase
|
|||
}
|
||||
|
||||
// Check minimum and maximum lengths.
|
||||
$length = is_scalar($value) ? iconv_strlen($value, 'UTF-8') : (is_countable($value) ? count($value) : 1);
|
||||
if (isset($this->minlength) && $this->minlength > 0 && $length < $this->minlength)
|
||||
$length = null;
|
||||
if (isset($this->minlength) && $this->minlength > 0)
|
||||
{
|
||||
throw new \Rhymix\Framework\Exceptions\QueryError('Variable ' . $this->var . ' for column ' . $column . ' must contain no less than ' . $this->minlength . ' characters');
|
||||
if ($length === null)
|
||||
{
|
||||
$length = is_scalar($value) ? mb_strlen($value, 'UTF-8') : (is_countable($value) ? count($value) : 1);
|
||||
}
|
||||
if ($length < $this->minlength)
|
||||
{
|
||||
throw new \Rhymix\Framework\Exceptions\QueryError('Variable ' . $this->var . ' for column ' . $column . ' must contain no less than ' . $this->minlength . ' characters');
|
||||
}
|
||||
}
|
||||
if (isset($this->maxlength) && $this->maxlength > 0 && $length > $this->maxlength)
|
||||
if (isset($this->maxlength) && $this->maxlength > 0)
|
||||
{
|
||||
throw new \Rhymix\Framework\Exceptions\QueryError('Variable ' . $this->var . ' for column ' . $column . ' must contain no more than ' . $this->maxlength . ' characters');
|
||||
if ($length === null)
|
||||
{
|
||||
$length = is_scalar($value) ? mb_strlen($value, 'UTF-8') : (is_countable($value) ? count($value) : 1);
|
||||
}
|
||||
if ($length > $this->maxlength)
|
||||
{
|
||||
throw new \Rhymix\Framework\Exceptions\QueryError('Variable ' . $this->var . ' for column ' . $column . ' must contain no more than ' . $this->maxlength . ' characters');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@ class TemplateParser_v2
|
|||
'cannot' => ['if ($this->_v2_checkCapability(2, %s)):', 'endif;'],
|
||||
'canany' => ['if ($this->_v2_checkCapability(3, %s)):', 'endif;'],
|
||||
'guest' => ['if (!$this->user->isMember()):', 'endif;'],
|
||||
'desktop' => ["if (!\\Context::get('m')):", 'endif;'],
|
||||
'mobile' => ["if (\\Context::get('m')):", 'endif;'],
|
||||
'desktop' => ['if (!$this->_v2_isMobile()):', 'endif;'],
|
||||
'mobile' => ['if ($this->_v2_isMobile()):', 'endif;'],
|
||||
'env' => ['if (!empty($_ENV[%s])):', 'endif;'],
|
||||
'else' => ['else:'],
|
||||
'elseif' => ['elseif (%s):'],
|
||||
|
|
@ -179,20 +179,45 @@ class TemplateParser_v2
|
|||
*/
|
||||
protected function _addContextSwitches(string $content): string
|
||||
{
|
||||
return preg_replace_callback('#(<script\b([^>]*)|</script)#i', function($match) {
|
||||
// Inline styles.
|
||||
$content = preg_replace_callback('#(?<=\s)(style=")([^"]*?)"#i', function($match) {
|
||||
return $match[1] . '<?php $this->config->context = \'CSS\'; ?>' . $match[2] . '<?php $this->config->context = \'HTML\'; ?>"';
|
||||
}, $content);
|
||||
|
||||
// Inline scripts.
|
||||
$content = preg_replace_callback('#(?<=\s)(href="javascript:|on[a-z]+=")([^"]*?)"#i', function($match) {
|
||||
return $match[1] . '<?php $this->config->context = \'JS\'; ?>' . $match[2] . '<?php $this->config->context = \'HTML\'; ?>"';
|
||||
}, $content);
|
||||
|
||||
// <style> tags.
|
||||
$content = preg_replace_callback('#(<style\b([^>]*)|</style)#i', function($match) {
|
||||
if (substr($match[1], 1, 1) === '/')
|
||||
{
|
||||
return '<?php $this->config->context = "HTML"; ?>' . $match[1];
|
||||
return '<?php $this->config->context = \'HTML\'; ?>' . $match[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
return $match[1] . '<?php $this->config->context = \'CSS\'; ?>';
|
||||
}
|
||||
}, $content);
|
||||
|
||||
// <script> tags that aren't links.
|
||||
$content = preg_replace_callback('#(<script\b([^>]*)|</script)#i', function($match) {
|
||||
if (substr($match[1], 1, 1) === '/')
|
||||
{
|
||||
return '<?php $this->config->context = \'HTML\'; ?>' . $match[1];
|
||||
}
|
||||
elseif (!str_contains($match[2] ?? '', 'src="'))
|
||||
{
|
||||
return $match[1] . '<?php $this->config->context = "JS"; ?>';
|
||||
return $match[1] . '<?php $this->config->context = \'JS\'; ?>';
|
||||
}
|
||||
else
|
||||
{
|
||||
return $match[0];
|
||||
}
|
||||
}, $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -203,7 +228,7 @@ class TemplateParser_v2
|
|||
*/
|
||||
protected static function _removeContextSwitches(string $content): string
|
||||
{
|
||||
return preg_replace('#<\?php \$this->config->context = "[A-Z]+"; \?>#', '', $content);
|
||||
return preg_replace('#<\?php \$this->config->context = \'[A-Z]+\'; \?>#', '', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -235,7 +260,7 @@ class TemplateParser_v2
|
|||
$basepath = \RX_BASEURL . $this->template->relative_dirname;
|
||||
|
||||
// Convert all src and srcset attributes.
|
||||
$regexp = '#(<(?:img|audio|video|script|input|source|link)\s[^>]*)(src|srcset|poster)="([^"]+)"#';
|
||||
$regexp = '#(<(?:img|audio|video|script|input|source|link)\s[^>]*)(?<=\s)(src|srcset|poster)="([^"]+)"#';
|
||||
$content = preg_replace_callback($regexp, function($match) use ($basepath) {
|
||||
if ($match[2] !== 'srcset')
|
||||
{
|
||||
|
|
@ -735,6 +760,7 @@ class TemplateParser_v2
|
|||
* @dd($var, $var, ...)
|
||||
* @stack('name')
|
||||
* @url(['mid' => $mid, 'act' => $act])
|
||||
* @widget('name', $args)
|
||||
*
|
||||
* @param string $content
|
||||
* @return string
|
||||
|
|
@ -748,7 +774,7 @@ class TemplateParser_v2
|
|||
|
||||
// Insert JSON, lang codes, and dumps.
|
||||
$parentheses = self::_getRegexpForParentheses(2);
|
||||
$content = preg_replace_callback('#(?<!@)@(json|lang|dump|stack|url)\x20?('. $parentheses . ')#', function($match) {
|
||||
$content = preg_replace_callback('#(?<!@)@(json|lang|dump|dd|stack|url|widget)\x20?('. $parentheses . ')#', function($match) {
|
||||
$args = self::_convertVariableScope(substr($match[2], 1, -1));
|
||||
switch ($match[1])
|
||||
{
|
||||
|
|
@ -757,7 +783,7 @@ class TemplateParser_v2
|
|||
'json_encode(%s, self::$_json_options2) : ' .
|
||||
'htmlspecialchars(json_encode(%s, self::$_json_options), \ENT_QUOTES, \'UTF-8\', false); ?>', $args, $args);
|
||||
case 'lang':
|
||||
return sprintf('<?php echo $this->config->context === \'JS\' ? escape_js($this->_v2_lang(%s)) : $this->_v2_lang(%s); ?>', $args, $args);
|
||||
return sprintf('<?php echo $this->config->context === \'HTML\' ? $this->_v2_lang(%s) : $this->_v2_escape($this->_v2_lang(%s)); ?>', $args, $args);
|
||||
case 'dump':
|
||||
return sprintf('<?php ob_start(); var_dump(%s); \$__dump = ob_get_clean(); echo rtrim(\$__dump); ?>', $args);
|
||||
case 'dd':
|
||||
|
|
@ -765,7 +791,9 @@ class TemplateParser_v2
|
|||
case 'stack':
|
||||
return sprintf('<?php echo implode("\n", self::\$_stacks[%s] ?? []) . "\n"; ?>', $args);
|
||||
case 'url':
|
||||
return sprintf('<?php echo $this->config->context === \'JS\' ? escape_js(getNotEncodedUrl(%s)) : getUrl(%s); ?>', $args, $args);
|
||||
return sprintf('<?php echo $this->config->context === \'HTML\' ? getUrl(%s) : $this->_v2_escape(getNotEncodedUrl(%s)); ?>', $args, $args);
|
||||
case 'widget':
|
||||
return sprintf('<?php echo \WidgetController::getInstance()->execute(%s); ?>', $args);
|
||||
default:
|
||||
return $match[0];
|
||||
}
|
||||
|
|
@ -797,6 +825,15 @@ class TemplateParser_v2
|
|||
return $this->_arrangeOutputFilters($match);
|
||||
}, $content);
|
||||
|
||||
// Exclude {single} curly braces in non-HTML contexts.
|
||||
$content = preg_replace_callback('#(<\?php \$this->config->context = \'(?:CSS|JS)\'; \?>)(.*?)(<\?php \$this->config->context = \'HTML\'; \?>)#s', function($match) {
|
||||
$match[2] = preg_replace_callback('#(?<!\{)\{(?!\s)([^{}]+?)\}#', function($m) {
|
||||
$warning = preg_match('#^\$\w#', $m[1]) ? '<?php trigger_error("Template v1 syntax not allowed in CSS/JS context", \E_USER_WARNING); ?>' : '';
|
||||
return '{' . $warning . $m[1] . '}';
|
||||
}, $match[2]);
|
||||
return $match[1] . $match[2] . $match[3];
|
||||
}, $content);
|
||||
|
||||
// Convert {single} curly braces.
|
||||
$content = preg_replace_callback('#(?<!\{)\{(?!\s)([^{}]+?)\}#', [$this, '_arrangeOutputFilters'], $content);
|
||||
|
||||
|
|
@ -943,11 +980,11 @@ class TemplateParser_v2
|
|||
switch($option)
|
||||
{
|
||||
case 'autocontext':
|
||||
return "\$this->config->context === 'JS' ? escape_js({$str2}) : htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false)";
|
||||
return "\$this->config->context === 'HTML' ? htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape({$str2})";
|
||||
case 'autocontext_json':
|
||||
return "\$this->config->context === 'JS' ? {$str2} : htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false)";
|
||||
case 'autocontext_lang':
|
||||
return "\$this->config->context === 'JS' ? escape_js({$str2}) : ({$str})";
|
||||
return "\$this->config->context === 'HTML' ? ({$str}) : \$this->_v2_escape({$str2})";
|
||||
case 'autoescape':
|
||||
return "htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false)";
|
||||
case 'autolang':
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
/**
|
||||
* Function library for Rhymix
|
||||
*
|
||||
* Copyright (c) Rhymix Developers and Contributors
|
||||
* Copyright (c) Poesis Inc. and Contributors
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -205,7 +205,7 @@ function escape($str, bool $double_escape = true, bool $except_lang_code = false
|
|||
*/
|
||||
function escape_css(string $str): string
|
||||
{
|
||||
return preg_replace('/[^a-zA-Z0-9_.#\/-]/', '', (string)$str);
|
||||
return preg_replace('/[^a-zA-Z0-9_.,#%\/\'()\x20-]/', '', (string)$str);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -680,7 +680,14 @@ function utf8_mbencode($str): string
|
|||
*/
|
||||
function utf8_normalize_spaces($str, bool $multiline = false): string
|
||||
{
|
||||
return $multiline ? preg_replace('/((?!\x0A)[\pZ\pC])+/u', ' ', (string)$str) : preg_replace('/[\pZ\pC]+/u', ' ', (string)$str);
|
||||
if ($multiline)
|
||||
{
|
||||
return preg_replace(['/((?!\x0A)[\pZ\pC])+/u', '/\x20*\x0A\x20*/'], [' ', "\n"], (string)$str);
|
||||
}
|
||||
else
|
||||
{
|
||||
return preg_replace('/[\pZ\pC]+/u', ' ', (string)$str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) Rhymix Developers and Contributors <devops@rhymix.org>
|
||||
* Copyright (c) Poesis Inc. and Contributors <devops@rhymix.org>
|
||||
* Copyright (c) NAVER <http://www.navercorp.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
|
|
|
|||
|
|
@ -185,6 +185,11 @@ body>.x,
|
|||
height: 24px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.x .x_pagination {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
.x .btn {
|
||||
color: #333;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1299,7 +1299,7 @@ jQuery(function($){
|
|||
position = {x:event.pageX, y:event.pageY};
|
||||
offset = getOffset($tr.get(0), ofspar);
|
||||
|
||||
$clone = $tr.attr('target', true).clone(true).appendTo($table);
|
||||
$clone = $tr.attr('target', true).clone(true).find('input').removeAttr('id name').end().appendTo($table);
|
||||
|
||||
// get colspan
|
||||
cols = ($th=$table.find('thead th')).length;
|
||||
|
|
|
|||
|
|
@ -290,30 +290,30 @@ class BoardController extends Board
|
|||
public function procBoardRevertDocument()
|
||||
{
|
||||
$update_id = Context::get('update_id');
|
||||
$logged_info = Context::get('logged_info');
|
||||
if(!$update_id)
|
||||
if (!$update_id)
|
||||
{
|
||||
throw new Rhymix\Framework\Exception('msg_no_update_id');
|
||||
}
|
||||
|
||||
$oDocumentController = DocumentController::getInstance();
|
||||
$update_log = DocumentModel::getUpdateLog($update_id);
|
||||
|
||||
if($logged_info->is_admin != 'Y')
|
||||
{
|
||||
$Exists_log = DocumentModel::getUpdateLogAdminisExists($update_log->document_srl);
|
||||
if($Exists_log === true)
|
||||
{
|
||||
throw new Rhymix\Framework\Exception('msg_admin_update_log');
|
||||
}
|
||||
}
|
||||
|
||||
if(!$update_log)
|
||||
if (!$update_log)
|
||||
{
|
||||
throw new Rhymix\Framework\Exception('msg_no_update_log');
|
||||
}
|
||||
|
||||
$oDocument = DocumentModel::getDocument($update_log->document_srl);
|
||||
if (!$oDocument->isGranted())
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\NotPermitted();
|
||||
}
|
||||
if (!$this->user->isAdmin())
|
||||
{
|
||||
if (DocumentModel::getUpdateLogAdminisExists($update_log->document_srl))
|
||||
{
|
||||
throw new Rhymix\Framework\Exception('msg_admin_update_log');
|
||||
}
|
||||
}
|
||||
|
||||
$obj = new stdClass();
|
||||
$obj->title = $update_log->title;
|
||||
$obj->document_srl = $update_log->document_srl;
|
||||
|
|
@ -322,10 +322,19 @@ class BoardController extends Board
|
|||
$obj->content = $update_log->content;
|
||||
$obj->update_log_setting = 'Y';
|
||||
$obj->reason_update = lang('board.revert_reason_update');
|
||||
$oDocumentController = DocumentController::getInstance();
|
||||
$output = $oDocumentController->updateDocument($oDocument, $obj);
|
||||
$this->setRedirectUrl(getNotEncodedUrl('', 'mid', Context::get('mid'),'act', '', 'document_srl', $update_log->document_srl));
|
||||
if (!$output->toBool())
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
|
||||
$this->add('mid', Context::get('mid'));
|
||||
$this->add('document_srl', $update_log->document_srl);
|
||||
$this->setRedirectUrl(getNotEncodedUrl([
|
||||
'mid' => Context::get('mid'),
|
||||
'document_srl' => $update_log->document_srl,
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1524,6 +1524,12 @@ class BoardView extends Board
|
|||
throw new Rhymix\Framework\Exception('msg_not_target');
|
||||
}
|
||||
|
||||
$features = Rhymix\Modules\Board\Models\Features::fromModuleInfo($this->module_info);
|
||||
if (!$features->{$target}->vote_log)
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\FeatureDisabled;
|
||||
}
|
||||
|
||||
$output = executeQueryArray($queryId, $args);
|
||||
if(!$output->toBool())
|
||||
{
|
||||
|
|
@ -1538,7 +1544,11 @@ class BoardView extends Board
|
|||
{
|
||||
if($log->point > 0)
|
||||
{
|
||||
if($log->member_srl == $vote_member_infos[$log->member_srl]->member_srl)
|
||||
if (isset($vote_member_infos[$log->member_srl]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!$features->{$target}->vote_up_log)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1546,7 +1556,11 @@ class BoardView extends Board
|
|||
}
|
||||
else
|
||||
{
|
||||
if($log->member_srl == $blame_member_infos[$log->member_srl]->member_srl)
|
||||
if (isset($blame_member_infos[$log->member_srl]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!$features->{$target}->vote_down_log)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1554,6 +1568,8 @@ class BoardView extends Board
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context::set('board_features', $features);
|
||||
Context::set('vote_member_info', $vote_member_infos);
|
||||
Context::set('blame_member_info', $blame_member_infos);
|
||||
$this->setTemplateFile('vote_log');
|
||||
|
|
|
|||
|
|
@ -61,8 +61,10 @@ class Features
|
|||
|
||||
// Document features
|
||||
$features->document->vote_up = ($document_config->use_vote_up ?? 'Y') !== 'N';
|
||||
$features->document->vote_up_log = ($document_config->use_vote_up ?? 'Y') === 'S';
|
||||
$features->document->vote_down = ($document_config->use_vote_down ?? 'Y') !== 'N';
|
||||
$features->document->vote_log = ($document_config->use_vote_up ?? 'Y') === 'S' || ($document_config->use_vote_down ?? 'Y') === 'S';
|
||||
$features->document->vote_down_log = ($document_config->use_vote_down ?? 'Y') === 'S';
|
||||
$features->document->vote_log = $features->document->vote_up_log || $features->document->vote_down_log;
|
||||
if (isset($document_config->allow_vote_cancel))
|
||||
{
|
||||
$features->document->cancel_vote = $document_config->allow_vote_cancel === 'Y';
|
||||
|
|
@ -92,8 +94,10 @@ class Features
|
|||
|
||||
// Comment features
|
||||
$features->comment->vote_up = ($comment_config->use_vote_up ?? 'Y') !== 'N';
|
||||
$features->comment->vote_up_log = ($comment_config->use_vote_up ?? 'Y') === 'S';
|
||||
$features->comment->vote_down = ($comment_config->use_vote_down ?? 'Y') !== 'N';
|
||||
$features->comment->vote_log = ($comment_config->use_vote_up ?? 'Y') === 'S' || ($comment_config->use_vote_down ?? 'Y') === 'S';
|
||||
$features->comment->vote_down_log = ($comment_config->use_vote_down ?? 'Y') === 'S';
|
||||
$features->comment->vote_log = $features->comment->vote_up_log || $features->comment->vote_down_log;
|
||||
if (isset($comment_config->allow_vote_cancel))
|
||||
{
|
||||
$features->comment->cancel_vote = $comment_config->allow_vote_cancel === 'Y';
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@
|
|||
<!--@if($board_features->document->vote_log)-->
|
||||
<a class="btn" href="{getUrl('', 'mid', $mid, 'act', 'dispBoardVoteLog', 'target_srl', $oDocument->document_srl, 'target', 'document')}"><i class="xi-list-ul"></i>{$lang->cmd_document_vote_user}</a>
|
||||
<!--@endif-->
|
||||
<!--@if($board_features->document->history)-->
|
||||
<!--@if($module_info->update_log == 'Y' && $grant->can('update_view'))-->
|
||||
<a cond="$update_view" class="btn" href="{getUrl('', 'mid', $mid, 'act', 'dispBoardUpdateLog', 'document_srl', $oDocument->document_srl)}"><i class="xi-list-ul"></i>{$lang->update_log}</a>
|
||||
<!--@endif-->
|
||||
<a cond="$oDocument->isEditable()" class="btn" href="{getUrl('', 'mid', $mid, 'act', 'dispBoardWrite', 'document_srl', $oDocument->document_srl)}"><i class="xi-eraser"></i>{$lang->cmd_modify}</a>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<column name="voted_count" type="number" size="11" default="0" notnull="notnull" index="idx_voted_count" />
|
||||
<column name="blamed_count" type="number" size="11" default="0" notnull="notnull" index="idx_blamed_count" />
|
||||
<column name="notify_message" type="char" size="1" default="N" notnull="notnull" />
|
||||
<column name="password" type="varchar" size="60" />
|
||||
<column name="password" type="varchar" size="250" />
|
||||
<column name="user_id" type="varchar" size="80" />
|
||||
<column name="user_name" type="varchar" size="80" notnull="notnull" />
|
||||
<column name="nick_name" type="varchar" size="80" notnull="notnull" index="idx_nick_name" />
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
|
|||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<form action="./" class="x_pagination">
|
||||
<input type="hidden" name="error_return_url" value="" />
|
||||
<input type="hidden" name="module" value="{$module}" />
|
||||
|
|
|
|||
|
|
@ -139,11 +139,11 @@ class CommunicationView extends communication
|
|||
|
||||
if ($message)
|
||||
{
|
||||
Context::addBrowserTitle($message->title);
|
||||
MemberView::setMemberPageBrowserTitle($message->title);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context::addBrowserTitle(lang('communication.message_box.' . $message_type));
|
||||
MemberView::setMemberPageBrowserTitle(lang('communication.message_box.' . $message_type));
|
||||
}
|
||||
|
||||
$this->setTemplateFile($template_filename);
|
||||
|
|
@ -186,7 +186,7 @@ class CommunicationView extends communication
|
|||
Context::set('message', $message);
|
||||
}
|
||||
|
||||
Context::addBrowserTitle($message->title ?? lang('cmd_view_message_box'));
|
||||
MemberView::setMemberPageBrowserTitle($message->title ?? lang('cmd_view_message_box'));
|
||||
$this->setTemplateFile('new_message');
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +313,7 @@ class CommunicationView extends communication
|
|||
$editor = $oEditorModel->getEditor(getNextSequence(), $option);
|
||||
$editor = $editor . "\n" . '<input type="hidden" name="temp_srl" value="" />' . "\n";
|
||||
Context::set('editor', $editor);
|
||||
Context::addBrowserTitle(lang('cmd_send_message'));
|
||||
MemberView::setMemberPageBrowserTitle(lang('cmd_send_message'));
|
||||
$this->setTemplateFile('send_message');
|
||||
|
||||
// Fix for skins that don't support window_type=self
|
||||
|
|
@ -387,7 +387,7 @@ class CommunicationView extends communication
|
|||
Context::set('friend_list', $output->data);
|
||||
Context::set('page_navigation', $output->page_navigation);
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_view_friend'));
|
||||
MemberView::setMemberPageBrowserTitle(lang('cmd_view_friend'));
|
||||
$this->setTemplateFile('friends');
|
||||
}
|
||||
|
||||
|
|
@ -460,7 +460,7 @@ class CommunicationView extends communication
|
|||
$friend_group_list = $oCommunicationModel->getFriendGroups();
|
||||
Context::set('friend_group_list', $friend_group_list);
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_add_friend'));
|
||||
MemberView::setMemberPageBrowserTitle(lang('cmd_add_friend'));
|
||||
$this->setTemplateFile('add_friend');
|
||||
|
||||
// Fix for skins that don't support window_type=self
|
||||
|
|
@ -524,7 +524,7 @@ class CommunicationView extends communication
|
|||
}
|
||||
}
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_add_friend_group'));
|
||||
MemberView::setMemberPageBrowserTitle(lang('cmd_add_friend_group'));
|
||||
$this->setTemplateFile('add_friend_group');
|
||||
|
||||
// Fix for skins that don't support window_type=self
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
<column name="comment_count" type="number" size="11" default="0" notnull="notnull" index="idx_comment_count" />
|
||||
<column name="trackback_count" type="number" size="11" default="0" notnull="notnull" index="idx_trackback_count" />
|
||||
<column name="uploaded_count" type="number" size="11" default="0" notnull="notnull" index="idx_uploaded_count" />
|
||||
<column name="password" type="varchar" size="60" />
|
||||
<column name="password" type="varchar" size="250" />
|
||||
<column name="user_id" type="varchar" size="80" />
|
||||
<column name="user_name" type="varchar" size="80" notnull="notnull" />
|
||||
<column name="nick_name" type="varchar" size="80" notnull="notnull" index="idx_nick_name" />
|
||||
|
|
|
|||
|
|
@ -72,16 +72,15 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="x_clearfix">
|
||||
<div class="x_btn-group x_pull-right">
|
||||
<a href="#manageForm" class="x_btn modalAnchor" data-value="trash">{$lang->trash}</a>
|
||||
<a href="#manageForm" class="x_btn modalAnchor" data-value="delete">{$lang->delete}</a>
|
||||
<a href="#manageForm" class="x_btn modalAnchor" data-value="move">{$lang->move}</a>
|
||||
<a href="#manageForm" class="x_btn modalAnchor" data-value="copy">{$lang->copy}</a>
|
||||
</div>
|
||||
<div class="x_btn-group x_pull-right">
|
||||
<a href="#manageForm" class="x_btn modalAnchor" data-value="trash">{$lang->trash}</a>
|
||||
<a href="#manageForm" class="x_btn modalAnchor" data-value="delete">{$lang->delete}</a>
|
||||
<a href="#manageForm" class="x_btn modalAnchor" data-value="move">{$lang->move}</a>
|
||||
<a href="#manageForm" class="x_btn modalAnchor" data-value="copy">{$lang->copy}</a>
|
||||
</div>
|
||||
</form>
|
||||
<form action="./" class="x_pagination x_pull-left" style="margin:-36px 0 0 0">
|
||||
|
||||
<form action="./" class="x_pagination">
|
||||
<input type="hidden" name="error_return_url" value="" />
|
||||
<input type="hidden" name="module" value="{$module}" />
|
||||
<input type="hidden" name="act" value="{$act}" />
|
||||
|
|
|
|||
|
|
@ -190,10 +190,15 @@ class Value
|
|||
{
|
||||
return $this->default;
|
||||
}
|
||||
elseif (is_array($this->options))
|
||||
|
||||
if (is_array($this->options))
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
elseif ($this->default)
|
||||
{
|
||||
return array_first($this->getOptions());
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1194,7 +1194,7 @@ class FileController extends File
|
|||
{
|
||||
$adjusted['type'] = 'mp4';
|
||||
}
|
||||
elseif (!empty($config->image_autoconv[$image_info['type']]))
|
||||
elseif (!empty($config->image_autoconv[$image_info['type']]) && tobool($config->image_autoconv[$image_info['type']]))
|
||||
{
|
||||
$adjusted['type'] = $config->image_autoconv[$image_info['type']];
|
||||
}
|
||||
|
|
@ -1723,14 +1723,18 @@ class FileController extends File
|
|||
// Get a full list of attachments
|
||||
$args = new stdClass;
|
||||
$args->module_srl = $module_srl;
|
||||
$output = executeQueryArray('file.getModuleFiles', $args);
|
||||
if(!$output->toBool() || empty($file_list = $output->data))
|
||||
$output = executeQueryArray('file.getModuleFilesProper', $args);
|
||||
if (!$output->toBool())
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
if (!$output->data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the file
|
||||
return $this->deleteFile($file_list);
|
||||
// Delete each file.
|
||||
return $this->deleteFile($output->data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1971,8 +1975,16 @@ class FileController extends File
|
|||
function triggerMoveDocument($obj)
|
||||
{
|
||||
$obj->upload_target_srls = $obj->document_srls;
|
||||
executeQuery('file.updateFileModule', $obj);
|
||||
executeQuery('file.updateFileModuleComment', $obj);
|
||||
$output = executeQuery('file.updateFileModule', $obj);
|
||||
if (!$output->toBool())
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
$output = executeQuery('file.updateFileModuleComment', $obj);
|
||||
if (!$output->toBool())
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
function triggerAddCopyDocument(&$obj)
|
||||
|
|
|
|||
31
modules/file/queries/getModuleFilesProper.xml
Normal file
31
modules/file/queries/getModuleFilesProper.xml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<query id="getModuleFilesProper" action="select">
|
||||
<tables>
|
||||
<table name="files" />
|
||||
<table name="documents" type="left join">
|
||||
<conditions>
|
||||
<condition operation="equal" column="files.upload_target_srl" default="documents.document_srl" />
|
||||
</conditions>
|
||||
</table>
|
||||
<table name="comments" type="left join">
|
||||
<conditions>
|
||||
<condition operation="equal" column="files.upload_target_srl" default="comments.comment_srl" />
|
||||
</conditions>
|
||||
</table>
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="files.*" />
|
||||
<column name="documents.module_srl" alias="d_module_srl" />
|
||||
<column name="comments.module_srl" alias="c_module_srl" />
|
||||
</columns>
|
||||
<conditions>
|
||||
<condition operation="equal" column="files.module_srl" var="module_srl" filter="number" notnull="notnull" />
|
||||
<group pipe="and">
|
||||
<condition operation="equal" column="documents.module_srl" var="module_srl" filter="number" notnull="notnull" />
|
||||
<condition operation="null" column="documents.module_srl" pipe="or" />
|
||||
</group>
|
||||
<group pipe="and">
|
||||
<condition operation="equal" column="comments.module_srl" var="module_srl" filter="number" notnull="notnull" />
|
||||
<condition operation="null" column="comments.module_srl" pipe="or" />
|
||||
</group>
|
||||
</conditions>
|
||||
</query>
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
<query id="updateFileModuleComment" action="update">
|
||||
<tables>
|
||||
<table name="files" />
|
||||
<table name="comments" />
|
||||
<table name="files" alias="f" />
|
||||
<table name="comments" alias="c" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="files.module_srl" var="module_srl" filter="number" notnull="notnull" />
|
||||
<column name="f.module_srl" var="module_srl" filter="number" notnull="notnull" />
|
||||
</columns>
|
||||
<conditions>
|
||||
<condition operation="equal" column="files.upload_target_srl" default="comments.comment_srl" />
|
||||
<condition operation="in" column="comments.document_srl" var="upload_target_srls" filter="number" notnull="notnull" pipe="and" />
|
||||
<condition operation="equal" column="f.upload_target_srl" default="c.comment_srl" />
|
||||
<condition operation="in" column="c.document_srl" var="upload_target_srls" filter="number" notnull="notnull" pipe="and" />
|
||||
</conditions>
|
||||
</query>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<p>
|
||||
Copyright © Rhymix Developers and Contributors<br />
|
||||
Copyright © Poesis Inc. and Contributors<br />
|
||||
Copyright © <a href="https://navercorp.com/" target="_blank">NAVER</a> & <a href="https://www.xehub.io/" target="_blank">XEHub</a>
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<p>
|
||||
Copyright © Rhymix Developers and Contributors<br />
|
||||
Copyright © Poesis Inc. and Contributors<br />
|
||||
Copyright © <a href="https://navercorp.com/" target="_blank">NAVER</a> & <a href="https://www.xehub.io/" target="_blank">XEHub</a>
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,6 @@
|
|||
<?php
|
||||
/* Copyright (C) Rhymix <https://rhymix.org> */
|
||||
/**
|
||||
* The view class of the integration_search module
|
||||
*
|
||||
* @author Rhymix Developers and Contributors <devops@rhymix.org>
|
||||
*/
|
||||
|
||||
class integration_searchMobile extends integration_searchView
|
||||
{
|
||||
/**
|
||||
* Search Result
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
function IS()
|
||||
{
|
||||
parent::IS();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -390,6 +390,7 @@ class LayoutAdminController extends Layout
|
|||
if(!is_dir($path)) FileHandler::makeDir($path);
|
||||
|
||||
$filename = strtolower($source['name']);
|
||||
$filename = Rhymix\Framework\Filters\FilenameFilter::clean($filename);
|
||||
if($filename != urlencode($filename))
|
||||
{
|
||||
$ext = substr(strrchr($filename,'.'),1);
|
||||
|
|
@ -407,9 +408,19 @@ class LayoutAdminController extends Layout
|
|||
*/
|
||||
function procLayoutAdminUserImageDelete()
|
||||
{
|
||||
$filename = Context::get('filename');
|
||||
$layout_srl = Context::get('layout_srl');
|
||||
$this->removeUserLayoutImage($layout_srl,$filename);
|
||||
if (!$layout_srl)
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\InvalidRequest();
|
||||
}
|
||||
|
||||
$filename = Context::get('filename');
|
||||
if (preg_match('!(\.\.|[/\\\\])!', $filename))
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\InvalidRequest();
|
||||
}
|
||||
|
||||
$this->removeUserLayoutImage($layout_srl, $filename);
|
||||
$this->setMessage('success_deleted');
|
||||
$this->setRedirectUrl(Context::get('error_return_url'));
|
||||
}
|
||||
|
|
@ -418,13 +429,19 @@ class LayoutAdminController extends Layout
|
|||
* delete image into user layout
|
||||
* @param int $layout_srl
|
||||
* @param string $filename
|
||||
* @return void
|
||||
* @return bool
|
||||
*/
|
||||
function removeUserLayoutImage($layout_srl,$filename)
|
||||
{
|
||||
$oLayoutModel = getModel('layout');
|
||||
$path = $oLayoutModel->getUserLayoutImagePath($layout_srl);
|
||||
@unlink($path . $filename);
|
||||
$path = FileHandler::getRealPath($path . Rhymix\Framework\Filters\FilenameFilter::clean($filename));
|
||||
if (!Rhymix\Framework\Storage::exists($path))
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\TargetNotFound();
|
||||
}
|
||||
|
||||
return Rhymix\Framework\Storage::delete($path);
|
||||
}
|
||||
|
||||
// deprecated
|
||||
|
|
|
|||
|
|
@ -1788,7 +1788,10 @@ class MemberController extends Member
|
|||
$chk_args = new stdClass;
|
||||
$chk_args->member_srl = $member_info->member_srl;
|
||||
$output = executeQuery('member.chkAuthMail', $chk_args);
|
||||
if($output->toBool() && $output->data->count != '0') throw new Rhymix\Framework\Exception('msg_user_not_confirmed');
|
||||
if ($output->toBool() && $output->data->count > 0)
|
||||
{
|
||||
throw new Rhymix\Framework\Exception(sprintf('msg_user_not_confirmed', $member_info->email_address));
|
||||
}
|
||||
}
|
||||
|
||||
// Get password reset method
|
||||
|
|
|
|||
|
|
@ -114,6 +114,24 @@ class MemberView extends Member
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the browser title for a page belonging to the member menu.
|
||||
*
|
||||
* @param string $title
|
||||
* @return void
|
||||
*/
|
||||
public static function setMemberPageBrowserTitle(string $title): void
|
||||
{
|
||||
$seo_title = config('seo.subpage_title') ?: '$SITE_TITLE - $SUBPAGE_TITLE';
|
||||
$seo_title = Context::replaceUserLang($seo_title);
|
||||
Context::setBrowserTitle($seo_title, array(
|
||||
'site_title' => Context::getSiteTitle(),
|
||||
'site_subtitle' => Context::getSiteSubtitle(),
|
||||
'subpage_title' => $title,
|
||||
'page' => Context::get('page') ?: 1,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Module index
|
||||
*/
|
||||
|
|
@ -181,7 +199,7 @@ class MemberView extends Member
|
|||
$member_info->group_list[$key] = Context::replaceUserLang($val, true);
|
||||
}
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_view_member_info'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_view_member_info'));
|
||||
Context::set('memberInfo', get_object_vars($member_info));
|
||||
|
||||
$extendForm = MemberModel::getCombineJoinForm($member_info);
|
||||
|
|
@ -376,7 +394,7 @@ class MemberView extends Member
|
|||
$member_config->agreement = $member_config->agreements[1]->content ?? '';
|
||||
|
||||
// Set a template file
|
||||
Context::addBrowserTitle(lang('cmd_signup'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_signup'));
|
||||
$this->setTemplateFile('signup_form');
|
||||
}
|
||||
|
||||
|
|
@ -413,7 +431,7 @@ class MemberView extends Member
|
|||
Context::set('identifierValue', $logged_info->user_id);
|
||||
}
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_modify_member_info'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_modify_member_info'));
|
||||
$this->setTemplateFile('rechecked_password');
|
||||
}
|
||||
|
||||
|
|
@ -499,7 +517,7 @@ class MemberView extends Member
|
|||
$this->addExtraFormValidatorMessage();
|
||||
|
||||
// Set a template file
|
||||
Context::addBrowserTitle(lang('cmd_modify_member_info'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_modify_member_info'));
|
||||
$this->setTemplateFile('modify_info');
|
||||
}
|
||||
|
||||
|
|
@ -550,7 +568,7 @@ class MemberView extends Member
|
|||
$oSecurity = new Security();
|
||||
$oSecurity->encodeHTML('document_list...title', 'search_target', 'search_keyword');
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_view_own_document'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_view_own_document'));
|
||||
$this->setTemplateFile('document_list');
|
||||
}
|
||||
|
||||
|
|
@ -598,7 +616,7 @@ class MemberView extends Member
|
|||
$oSecurity = new Security();
|
||||
$oSecurity->encodeHTML('search_target', 'search_keyword');
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_view_own_comment'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_view_own_comment'));
|
||||
$this->setTemplateFile('comment_list');
|
||||
}
|
||||
|
||||
|
|
@ -708,7 +726,7 @@ class MemberView extends Member
|
|||
$security = new Security($output->data);
|
||||
$security->encodeHTML('..nick_name');
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_view_scrapped_document'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_view_scrapped_document'));
|
||||
$this->setTemplateFile('scrapped_list');
|
||||
}
|
||||
|
||||
|
|
@ -743,7 +761,7 @@ class MemberView extends Member
|
|||
Context::set('document_list', $output->data);
|
||||
Context::set('page_navigation', $output->page_navigation);
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_view_saved_document'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_view_saved_document'));
|
||||
$this->setTemplateFile('saved_list');
|
||||
}
|
||||
|
||||
|
|
@ -783,7 +801,7 @@ class MemberView extends Member
|
|||
$output = executeQueryArray('member.getMemberDevice', $args);
|
||||
Context::set('registered_devices', $output->data);
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_view_active_logins'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_view_active_logins'));
|
||||
$this->setTemplateFile('active_logins');
|
||||
}
|
||||
|
||||
|
|
@ -822,7 +840,7 @@ class MemberView extends Member
|
|||
}
|
||||
|
||||
// Set a template file
|
||||
Context::addBrowserTitle(lang('cmd_login'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_login'));
|
||||
$this->setTemplateFile('login_form');
|
||||
}
|
||||
|
||||
|
|
@ -858,7 +876,7 @@ class MemberView extends Member
|
|||
Context::set('formValue', $member_info->email_address);
|
||||
}
|
||||
// Set a template file
|
||||
Context::addBrowserTitle(lang('cmd_modify_member_password'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_modify_member_password'));
|
||||
$this->setTemplateFile('modify_password');
|
||||
}
|
||||
|
||||
|
|
@ -893,7 +911,7 @@ class MemberView extends Member
|
|||
Context::set('formValue', $member_info->email_address);
|
||||
}
|
||||
// Set a template file
|
||||
Context::addBrowserTitle(lang('msg_leave_member'));
|
||||
self::setMemberPageBrowserTitle(lang('msg_leave_member'));
|
||||
$this->setTemplateFile('leave_form');
|
||||
}
|
||||
|
||||
|
|
@ -943,7 +961,7 @@ class MemberView extends Member
|
|||
Context::set('identifier', $this->member_config->identifier);
|
||||
Context::set('enable_find_account_question', 'N');
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_find_member_account'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_find_member_account'));
|
||||
$this->setTemplateFile('find_member_account');
|
||||
}
|
||||
|
||||
|
|
@ -962,7 +980,7 @@ class MemberView extends Member
|
|||
return;
|
||||
}
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_resend_auth_mail'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_resend_auth_mail'));
|
||||
$this->setTemplateFile('resend_auth_mail');
|
||||
}
|
||||
|
||||
|
|
@ -982,7 +1000,7 @@ class MemberView extends Member
|
|||
|
||||
$_SESSION['rechecked_password_step'] = 'INPUT_DATA';
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_modify_member_email_address'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_modify_member_email_address'));
|
||||
$this->setTemplateFile('modify_email_address');
|
||||
}
|
||||
|
||||
|
|
@ -1101,7 +1119,7 @@ class MemberView extends Member
|
|||
Context::set('nickname_list', $output->data);
|
||||
Context::set('page_navigation', $output->page_navigation);
|
||||
|
||||
Context::addBrowserTitle(lang('cmd_modify_nickname_log'));
|
||||
self::setMemberPageBrowserTitle(lang('cmd_modify_nickname_log'));
|
||||
$this->setTemplateFile('member_nick');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class NcenterliteView extends Ncenterlite
|
|||
Context::set('ncenterlite_list', $output->data);
|
||||
Context::set('page_navigation', $output->page_navigation);
|
||||
|
||||
Context::addBrowserTitle(lang('ncenterlite_my_list'));
|
||||
MemberView::setMemberPageBrowserTitle(lang('ncenterlite_my_list'));
|
||||
$this->setTemplateFileOrDefault('NotifyList');
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ class NcenterliteView extends Ncenterlite
|
|||
Context::set('sms_available', Rhymix\Framework\SMS::getDefaultDriver()->getName() !== 'Dummy');
|
||||
Context::set('push_available', count(Rhymix\Framework\Config::get('push.types') ?? []) > 0);
|
||||
|
||||
Context::addBrowserTitle(lang('ncenterlite_my_settings'));
|
||||
MemberView::setMemberPageBrowserTitle(lang('ncenterlite_my_settings'));
|
||||
$this->setTemplateFileOrDefault('userconfig');
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ class NcenterliteView extends Ncenterlite
|
|||
Context::set('unsubscribe_list', $output->data);
|
||||
Context::set('page_navigation', $output->page_navigation);
|
||||
|
||||
Context::addBrowserTitle(lang('unsubscribe_list'));
|
||||
MemberView::setMemberPageBrowserTitle(lang('unsubscribe_list'));
|
||||
$this->setTemplateFileOrDefault('unsubscribeList');
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +230,7 @@ class NcenterliteView extends Ncenterlite
|
|||
Context::set('text', $text);
|
||||
Context::set('type', $type);
|
||||
|
||||
Context::addBrowserTitle(lang('unsubscribe_list'));
|
||||
MemberView::setMemberPageBrowserTitle(lang('unsubscribe_list'));
|
||||
$this->setTemplateFileOrDefault('unsubscribe');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -305,8 +305,17 @@ class PageAdminView extends Page
|
|||
Context::set('oDocument', $oDocument);
|
||||
Context::set('mid', $this->module_info->mid);
|
||||
|
||||
$this->setLayoutFile('');
|
||||
$this->setTemplateFile('article_content_modify');
|
||||
$this->setLayoutAndTemplatePaths($isMobile ? 'M' : 'P', $this->module_info);
|
||||
$skin_path = rtrim($this->getTemplatePath(), '/') . '/';
|
||||
if (file_exists($skin_path . 'content_modify.blade.php') || file_exists($skin_path . 'content_modify.html'))
|
||||
{
|
||||
$this->setTemplateFile('content_modify');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->setTemplatePath($this->module_path . 'tpl');
|
||||
$this->setTemplateFile('article_content_modify');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -57,10 +57,10 @@ class PointModel extends Point
|
|||
}
|
||||
|
||||
// Get from file cache
|
||||
$cache_path = sprintf(RX_BASEDIR . 'files/member_extra_info/point/%s', getNumberingPath($member_srl));
|
||||
$cache_filename = sprintf('%s/%d.cache.txt', $cache_path, $member_srl);
|
||||
if (!$from_db && !$use_cache)
|
||||
{
|
||||
$cache_path = sprintf(RX_BASEDIR . 'files/member_extra_info/point/%s', getNumberingPath($member_srl));
|
||||
$cache_filename = sprintf('%s/%d.cache.txt', $cache_path, $member_srl);
|
||||
if (file_exists($cache_filename))
|
||||
{
|
||||
$point = trim(Rhymix\Framework\Storage::read($cache_filename));
|
||||
|
|
|
|||
|
|
@ -383,60 +383,49 @@ class WidgetController extends Widget
|
|||
$widget_cache = intval(floatval($widget_cache) * 60);
|
||||
}
|
||||
|
||||
/**
|
||||
* Even if the cache number and value of the cache and return it to extract data
|
||||
*/
|
||||
// If widget cache is disabled, just execute the widget and return the result.
|
||||
if(!$ignore_cache && !$widget_cache)
|
||||
{
|
||||
$oWidget = $this->getWidgetObject($widget);
|
||||
if(!$oWidget || !method_exists($oWidget, 'proc')) return;
|
||||
if (!$oWidget || !method_exists($oWidget, 'proc'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$widget_content = $oWidget->proc($args);
|
||||
$widget_content = Context::replaceUserLang($widget_content);
|
||||
return $widget_content;
|
||||
return Context::replaceUserLang($widget_content);
|
||||
}
|
||||
|
||||
$cache_data = Rhymix\Framework\Cache::get('widget_cache:' . $widget_sequence);
|
||||
if ($cache_data)
|
||||
// If cached data exists, return it.
|
||||
$cache_key = 'widget_cache:' . $widget_sequence . ':' . $lang_type;
|
||||
$cache_data = Rhymix\Framework\Cache::get($cache_key);
|
||||
if (is_object($cache_data) && isset($cache_data->assets))
|
||||
{
|
||||
// Load the variables, need to load the LESS or SCSS files.
|
||||
if(is_object($cache_data))
|
||||
foreach ($cache_data->assets as $asset)
|
||||
{
|
||||
foreach ($cache_data->variables as $key => $value)
|
||||
{
|
||||
Context::set($key, $value);
|
||||
}
|
||||
$cache_data = $cache_data->content;
|
||||
Context::loadFile($asset);
|
||||
}
|
||||
return str_replace('<!--#Meta:', '<!--Meta:', $cache_data);
|
||||
return Context::replaceUserLang($cache_data->content);
|
||||
}
|
||||
|
||||
// Otherwise, execute the widget, cache the result, and return it.
|
||||
$oWidget = $this->getWidgetObject($widget);
|
||||
if(!$oWidget || !method_exists($oWidget,'proc')) return;
|
||||
if (!$oWidget || !method_exists($oWidget, 'proc'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$oFrontEndFileHandler = FrontEndFileHandler::getInstance();
|
||||
$oFrontEndFileHandler->startLog();
|
||||
|
||||
$widget_content = $oWidget->proc($args);
|
||||
$widget_content = Context::replaceUserLang($widget_content);
|
||||
|
||||
Rhymix\Framework\Cache::set('widget_cache:' . $widget_sequence, $widget_content, $widget_cache, true);
|
||||
$cache_data = new stdClass;
|
||||
$cache_data->assets = $oFrontEndFileHandler->endLog();
|
||||
$cache_data->content = $widget_content;
|
||||
Rhymix\Framework\Cache::set($cache_key, $cache_data, $widget_cache, true);
|
||||
|
||||
// Keep the variables, need to load the LESS or SCSS files.
|
||||
if(preg_match_all('/<!--#Meta:([a-z0-9\_\-\/\.\@\:]+)(\?\$\_\_Context\-\>[a-z0-9\_\-\/\.\@\:]+)?-->/is', $widget_content, $widget_var_matches, PREG_SET_ORDER))
|
||||
{
|
||||
$cache_content = new stdClass();
|
||||
$cache_content->content = $widget_content;
|
||||
$cache_content->variables = new stdClass();
|
||||
foreach($widget_var_matches as $matches)
|
||||
{
|
||||
if(isset($matches[2]) && $matches[2])
|
||||
{
|
||||
$key = str_replace('?$__Context->', '', $matches[2]);
|
||||
$cache_content->variables->{$key} = Context::get($key);
|
||||
}
|
||||
}
|
||||
Rhymix\Framework\Cache::set('widget_cache:' . $widget_sequence, $cache_content, $widget_cache, true);
|
||||
}
|
||||
|
||||
return $widget_content;
|
||||
return Context::replaceUserLang($widget_content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -450,14 +439,21 @@ class WidgetController extends Widget
|
|||
// Save for debug run-time widget
|
||||
$start = microtime(true);
|
||||
|
||||
// urldecode the value of args haejum
|
||||
$object_vars = get_object_vars($args);
|
||||
if(count($object_vars))
|
||||
// Type juggling
|
||||
if (is_array($args))
|
||||
{
|
||||
foreach($object_vars as $key => $val)
|
||||
$args = (object)$args;
|
||||
}
|
||||
|
||||
// Apply urldecode for backward compatibility
|
||||
if ($escaped)
|
||||
{
|
||||
foreach (get_object_vars($args) ?: [] as $key => $val)
|
||||
{
|
||||
if(in_array($key, array('widgetbox_content','body','class','style','widget_sequence','widget','widget_padding_left','widget_padding_top','widget_padding_bottom','widget_padding_right','widgetstyle','document_srl'))) continue;
|
||||
if($escaped) $args->{$key} = utf8RawUrlDecode($val);
|
||||
if (!in_array($key, ['body', 'class', 'style', 'document_srl', 'widget', 'widget_sequence', 'widgetstyle', 'widgetbox_content', 'widget_padding_left', 'widget_padding_top', 'widget_padding_bottom', 'widget_padding_right']))
|
||||
{
|
||||
$args->{$key} = utf8RawUrlDecode($val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -810,10 +806,14 @@ class WidgetController extends Widget
|
|||
|
||||
if($vars->widget_sequence)
|
||||
{
|
||||
Rhymix\Framework\Cache::delete('widget_cache:' . $vars->widget_sequence);
|
||||
$lang_type = Context::getLangType();
|
||||
Rhymix\Framework\Cache::delete('widget_cache:' . $vars->widget_sequence . ':' . $lang_type);
|
||||
}
|
||||
|
||||
if($vars->widget_cache>0) $vars->widget_sequence = getNextSequence();
|
||||
if($vars->widget_cache > 0)
|
||||
{
|
||||
$vars->widget_sequence = getNextSequence();
|
||||
}
|
||||
|
||||
$attribute = array();
|
||||
foreach($vars as $key => $val)
|
||||
|
|
|
|||
26
tests/_data/template/v2contextual.executed.html
Normal file
26
tests/_data/template/v2contextual.executed.html
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
<a href="javascript:alert('Hello \u003C\u0022world\u0022\u003E (\u0027string\u0027) variable.jpg')">
|
||||
Hello <"world"> ('string') variable.jpg</p>
|
||||
|
||||
<p onclick="location.href = 'Hello \u003C\u0022world\u0022\u003E (\u0027string\u0027) variable.jpg';">
|
||||
<span style="font: Hello <"world"> ('string') variable.jpg">
|
||||
Hello <"world"> ('string') variable.jpg </span>
|
||||
</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
const str = "Hello \u003C\u0022world\u0022\u003E ('string') variable.jpg";
|
||||
const tpl = `template literal with ${var} inside`;
|
||||
const fun = function() {
|
||||
const foo = 'Hello \u003C\u0022world\u0022\u003E (\u0027string\u0027) variable.jpg';
|
||||
const bar = 'Hello <"world"> ('string') variable.jpg';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body{background-image: url('Hello <"world"> ('string') variable.jpg')}
|
||||
</style>
|
||||
|
||||
<ul class="test">
|
||||
<li>Hello <"world"> ('string') variable.jpg</li>
|
||||
<li>Hello <"world"> ('string') variable.jpg</li>
|
||||
</ul>
|
||||
29
tests/_data/template/v2contextual.html
Normal file
29
tests/_data/template/v2contextual.html
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
@version(2)
|
||||
|
||||
<a href="javascript:alert('{{ $var }}')">
|
||||
{{ $var }}
|
||||
</p>
|
||||
|
||||
<p onclick="location.href = '{{ $var }}';">
|
||||
<span style="font: {{ $var }}">
|
||||
{{ $var }}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
const str = @json($var);
|
||||
const tpl = `template literal with ${var} inside`;
|
||||
const fun = function() {
|
||||
const foo = '{{ $var }}';
|
||||
const bar = '{{ $var|noescape }}';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body{background-image: url('{{ $var }}')}
|
||||
</style>
|
||||
|
||||
<ul class="test">
|
||||
<li>{{ $var }}</li>
|
||||
<li>{{ $var|noescape }}</li>
|
||||
</ul>
|
||||
|
|
@ -15,16 +15,16 @@
|
|||
{{ $foo }}
|
||||
|
||||
|
||||
<form action="<?php echo $this->config->context === 'JS' ? escape_js(\RX_BASEURL) : htmlspecialchars(\RX_BASEURL, \ENT_QUOTES, 'UTF-8', false); ?>" method="post">
|
||||
<form action="<?php echo $this->config->context === 'HTML' ? htmlspecialchars(\RX_BASEURL, \ENT_QUOTES, 'UTF-8', false) : $this->_v2_escape(\RX_BASEURL); ?>" method="post">
|
||||
<input type="hidden" name="_rx_csrf_token" value="<?php echo \Rhymix\Framework\Session::getGenericToken(); ?>" />
|
||||
<input type="text"<?php if (Context::getInstance()->get('foo')): ?> required="required"<?php endif; ?>>
|
||||
<input type="text" value="<?php echo $this->config->context === 'JS' ? escape_js($__Context->bar[0] ?? '') : htmlspecialchars($__Context->bar[0] ?? '', \ENT_QUOTES, 'UTF-8', false); ?>"<?php if ($__Context->bar[3] === 'da'): ?> required="required"<?php endif; ?> />
|
||||
<input type="text" value="<?php echo $this->config->context === 'HTML' ? htmlspecialchars($__Context->bar[0] ?? '', \ENT_QUOTES, 'UTF-8', false) : $this->_v2_escape($__Context->bar[0] ?? ''); ?>"<?php if ($__Context->bar[3] === 'da'): ?> required="required"<?php endif; ?> />
|
||||
</form>
|
||||
|
||||
<div<?php if (!(isset($__Context->baz))): ?> class="foobar"<?php endif; ?>>
|
||||
<?php if ($__Context->foo || $__Context->bar): ?>
|
||||
<p>Hello <?php if ($__Context->bar): ?><?php echo $__Context->foo ?? ''; ?><?php endif; ?></p>
|
||||
<p><?php echo $this->config->context === 'JS' ? escape_js(implode('|', array_map(function($i) { return strtoupper($i); }, $__Context->bar))) : htmlspecialchars(implode('|', array_map(function($i) { return strtoupper($i); }, $__Context->bar)), \ENT_QUOTES, 'UTF-8', false); ?></p>
|
||||
<p><?php echo $this->config->context === 'HTML' ? htmlspecialchars(implode('|', array_map(function($i) { return strtoupper($i); }, $__Context->bar)), \ENT_QUOTES, 'UTF-8', false) : $this->_v2_escape(implode('|', array_map(function($i) { return strtoupper($i); }, $__Context->bar))); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<div>
|
||||
<?php if (empty($__Context->nosuchvar)): ?>
|
||||
<img src="/rhymix/tests/_data/template/bar/rhymix.svg" alt="unit tests are cool" />
|
||||
<span <?php if ($__Context->k >= 2): ?>class="<?php echo $this->config->context === 'JS' ? escape_js($__Context->val ?? '') : htmlspecialchars($__Context->val ?? '', \ENT_QUOTES, 'UTF-8', false); ?>"<?php endif; ?>></span>
|
||||
<span <?php if ($__Context->k >= 2): ?>class="<?php echo $this->config->context === 'HTML' ? htmlspecialchars($__Context->val ?? '', \ENT_QUOTES, 'UTF-8', false) : $this->_v2_escape($__Context->val ?? ''); ?>"<?php endif; ?>></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php $this->_v2_incrLoopVar($__loop_RANDOM_LOOP_ID); endforeach; $this->_v2_removeLoopVar($__loop_RANDOM_LOOP_ID); unset($__loop_RANDOM_LOOP_ID); else: ?><div>Nothing here...</div><?php endif; ?>
|
||||
|
|
@ -42,8 +42,8 @@
|
|||
<?php (function($__filename, $__vars, $__varname, $__empty = null) { if (!$__vars): $__vars = []; if ($__empty): $__filename = $__empty; $__vars[] = ''; endif; endif; foreach ($__vars as $__var): echo $this->_v2_include("include", $__filename, [(string)$__varname => $__var]); endforeach; })('incl/eachtest', $__Context->bar, 'var'); ?>
|
||||
<?php (function($__filename, $__vars, $__varname, $__empty = null) { if (!$__vars): $__vars = []; if ($__empty): $__filename = $__empty; $__vars[] = ''; endif; endif; foreach ($__vars as $__var): echo $this->_v2_include("include", $__filename, [(string)$__varname => $__var]); endforeach; })('incl/eachtest', [], 'anything', 'incl/empty'); ?>
|
||||
|
||||
<?php if (!\Context::get('m')): ?>
|
||||
<p>The full class name is <?php echo htmlspecialchars(get_class(new Rhymix\Framework\Push), \ENT_QUOTES, 'UTF-8', true); ?>, <?php echo $this->config->context === 'JS' ? escape_js(Rhymix\Framework\Push::class) : htmlspecialchars(Rhymix\Framework\Push::class, \ENT_QUOTES, 'UTF-8', false); ?> really.</p>
|
||||
<?php if (!$this->_v2_isMobile()): ?>
|
||||
<p>The full class name is <?php echo htmlspecialchars(get_class(new Rhymix\Framework\Push), \ENT_QUOTES, 'UTF-8', true); ?>, <?php echo $this->config->context === 'HTML' ? htmlspecialchars(Rhymix\Framework\Push::class, \ENT_QUOTES, 'UTF-8', false) : $this->_v2_escape(Rhymix\Framework\Push::class); ?> really.</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="barContainer" data-bar="<?php echo $this->config->context === 'JS' ? json_encode($__Context->bar ?? '', self::$_json_options) : htmlspecialchars(json_encode($__Context->bar ?? '', self::$_json_options), \ENT_QUOTES, 'UTF-8', false); ?>">
|
||||
|
|
@ -60,7 +60,11 @@
|
|||
]); ?>></span>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript"<?php $this->config->context = "JS"; ?>>
|
||||
const foo = '<?php echo $this->config->context === 'JS' ? escape_js($__Context->foo ?? '') : htmlspecialchars($__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false); ?>';
|
||||
<script type="text/javascript"<?php $this->config->context = 'JS'; ?>>
|
||||
const foo = '<?php echo $this->config->context === 'HTML' ? htmlspecialchars($__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false) : $this->_v2_escape($__Context->foo ?? ''); ?>';
|
||||
const bar = <?php echo $this->config->context === 'JS' ? json_encode($__Context->bar, self::$_json_options2) : htmlspecialchars(json_encode($__Context->bar, self::$_json_options), \ENT_QUOTES, 'UTF-8', false); ?>;
|
||||
<?php $this->config->context = "HTML"; ?></script>
|
||||
<?php $this->config->context = 'HTML'; ?></script>
|
||||
|
||||
<style<?php $this->config->context = 'CSS'; ?>>
|
||||
body { background-color: <?php echo $this->config->context === 'HTML' ? htmlspecialchars('#ffffff', \ENT_QUOTES, 'UTF-8', false) : $this->_v2_escape('#ffffff'); ?>; }
|
||||
<?php $this->config->context = 'HTML'; ?></style>
|
||||
|
|
|
|||
|
|
@ -60,3 +60,7 @@
|
|||
const foo = 'FOOFOO\u003C\u0022FOO\u0022\u003EBAR';
|
||||
const bar = ["Rhy","miX","is","da","BEST!"];
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body { background-color: #ffffff; }
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -64,3 +64,7 @@
|
|||
const foo = '{{ $foo }}';
|
||||
const bar = @json($bar);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body { background-color: {{ '#ffffff' }}; }
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -248,11 +248,39 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
$this->assertEquals($target, $this->_parse($source));
|
||||
}
|
||||
|
||||
public function testContextSwitches()
|
||||
{
|
||||
// <script> tag
|
||||
$source = '<script type="text/javascript"> foobar(); </script>';
|
||||
$target = '<script type="text/javascript"<?php $this->config->context = \'JS\'; ?>> foobar(); <?php $this->config->context = \'HTML\'; ?></script>';
|
||||
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||
|
||||
// Inline script in link href
|
||||
$source = '<a href="javascript:void(0)">Hello</a>';
|
||||
$target = '<a href="javascript:<?php $this->config->context = \'JS\'; ?>void(0)<?php $this->config->context = \'HTML\'; ?>">Hello</a>';
|
||||
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||
|
||||
// Inline script in event handler
|
||||
$source = '<div class="foo" onClick="bar.barr()">Hello</div>';
|
||||
$target = '<div class="foo" onClick="<?php $this->config->context = \'JS\'; ?>bar.barr()<?php $this->config->context = \'HTML\'; ?>">Hello</div>';
|
||||
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||
|
||||
// <style> tag
|
||||
$source = '<style> body { font-size: 16px; } </style>';
|
||||
$target = '<style<?php $this->config->context = \'CSS\'; ?>> body { font-size: 16px; } <?php $this->config->context = \'HTML\'; ?></style>';
|
||||
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||
|
||||
// Inline style
|
||||
$source = '<div style="background-color: #ffffff;" class="foobar"><span></span></div>';
|
||||
$target = '<div style="<?php $this->config->context = \'CSS\'; ?>background-color: #ffffff;<?php $this->config->context = \'HTML\'; ?>" class="foobar"><span></span></div>';
|
||||
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||
}
|
||||
|
||||
public function testEchoStatements()
|
||||
{
|
||||
// Basic usage of XE-style single braces
|
||||
$source = '{$var}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->var ?? '') : htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(\$__Context->var ?? ''); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Single braces with space at beginning will not be parsed
|
||||
|
|
@ -262,22 +290,22 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
|
||||
// Single braces with space at end are OK
|
||||
$source = '{$var }';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->var ?? '') : htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(\$__Context->var ?? ''); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Correct handling of object property and array access
|
||||
$source = '{Context::getRequestVars()->$foo[$bar]}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(Context::getRequestVars()->{\$__Context->foo}[\$__Context->bar]) : htmlspecialchars(Context::getRequestVars()->{\$__Context->foo}[\$__Context->bar], \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(Context::getRequestVars()->{\$__Context->foo}[\$__Context->bar], \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(Context::getRequestVars()->{\$__Context->foo}[\$__Context->bar]); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Basic usage of Blade-style double braces
|
||||
$source = '{{ $var }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->var ?? '') : htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(\$__Context->var ?? ''); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Double braces without spaces are OK
|
||||
$source = '{{$var}}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->var ?? '') : htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(\$__Context->var ?? ''); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Literal double braces
|
||||
|
|
@ -297,7 +325,7 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
|
||||
// Multiline echo statement
|
||||
$source = '{{ $foo ?' . "\n" . ' date($foo) :' . "\n" . ' toBool($bar) }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->foo ? date(\$__Context->foo) : toBool(\$__Context->bar)) : htmlspecialchars(\$__Context->foo ?\n date(\$__Context->foo) :\n toBool(\$__Context->bar), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(\$__Context->foo ?\n date(\$__Context->foo) :\n toBool(\$__Context->bar), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(\$__Context->foo ? date(\$__Context->foo) : toBool(\$__Context->bar)); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
}
|
||||
|
||||
|
|
@ -339,11 +367,11 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
$source = '{{ $lang->cmd_hello_world }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->lang->cmd_hello_world) : (\$__Context->lang->cmd_hello_world); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? (\$__Context->lang->cmd_hello_world) : \$this->_v2_escape(\$__Context->lang->cmd_hello_world); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
$source = '{{ $user_lang->user_lang_1234567890 }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->user_lang->user_lang_1234567890 ?? '') : (\$__Context->user_lang->user_lang_1234567890 ?? ''); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? (\$__Context->user_lang->user_lang_1234567890 ?? '') : \$this->_v2_escape(\$__Context->user_lang->user_lang_1234567890 ?? ''); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Escape
|
||||
|
|
@ -366,11 +394,6 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
$target = "<?php echo escape_js(\$__Context->foo ?? ''); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Context-aware escape
|
||||
$source = '<script type="text/javascript"> foobar(); </script>';
|
||||
$target = '<script type="text/javascript"<?php $this->config->context = "JS"; ?>> foobar(); <?php $this->config->context = "HTML"; ?></script>';
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// JSON using context-aware escape
|
||||
$source = '{{ $foo|json }}';
|
||||
$target = implode('', [
|
||||
|
|
@ -382,12 +405,12 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
|
||||
// strip_tags
|
||||
$source = '{{ $foo|strip }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(strip_tags(\$__Context->foo ?? '')) : htmlspecialchars(strip_tags(\$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(strip_tags(\$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(strip_tags(\$__Context->foo ?? '')); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// strip_tags (alternate name)
|
||||
$source = '{{ $foo|upper|strip_tags }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(strip_tags(strtoupper(\$__Context->foo ?? ''))) : htmlspecialchars(strip_tags(strtoupper(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(strip_tags(strtoupper(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(strip_tags(strtoupper(\$__Context->foo ?? ''))); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Trim
|
||||
|
|
@ -397,12 +420,12 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
|
||||
// URL encode
|
||||
$source = '{{ $foo|trim|urlencode }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(rawurlencode(trim(\$__Context->foo ?? ''))) : htmlspecialchars(rawurlencode(trim(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(rawurlencode(trim(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(rawurlencode(trim(\$__Context->foo ?? ''))); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Lowercase
|
||||
$source = '{{ $foo|trim|lower }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(strtolower(trim(\$__Context->foo ?? ''))) : htmlspecialchars(strtolower(trim(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(strtolower(trim(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(strtolower(trim(\$__Context->foo ?? ''))); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Uppercase
|
||||
|
|
@ -422,37 +445,37 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
|
||||
// Array join (default joiner is comma)
|
||||
$source = '{{ $foo|join }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(implode(', ', \$__Context->foo ?? '')) : htmlspecialchars(implode(', ', \$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(implode(', ', \$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(implode(', ', \$__Context->foo ?? '')); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Array join (custom joiner)
|
||||
$source = '{{ $foo|join:"!@!" }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(implode(\"!@!\", \$__Context->foo ?? '')) : htmlspecialchars(implode(\"!@!\", \$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(implode(\"!@!\", \$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(implode(\"!@!\", \$__Context->foo ?? '')); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Date conversion (default format)
|
||||
$source = '{{ $item->regdate | date }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'Y-m-d H:i:s')) : htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'Y-m-d H:i:s'), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'Y-m-d H:i:s'), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'Y-m-d H:i:s')); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Date conversion (custom format)
|
||||
$source = "{{ \$item->regdate | date:'n/j H:i' }}";
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'n/j H:i')) : htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'n/j H:i'), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'n/j H:i'), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'n/j H:i')); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Date conversion (custom format in variable)
|
||||
$source = "{{ \$item->regdate | date:\$format }}";
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), \$__Context->format)) : htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), \$__Context->format), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), \$__Context->format), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), \$__Context->format)); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Number format
|
||||
$source = '{{ $num | format }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(number_format(\$__Context->num ?? '')) : htmlspecialchars(number_format(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(number_format(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(number_format(\$__Context->num ?? '')); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Number format (alternate name)
|
||||
$source = '{{ $num | number_format }}';
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(number_format(\$__Context->num ?? '')) : htmlspecialchars(number_format(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(number_format(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(number_format(\$__Context->num ?? '')); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Number format (custom format)
|
||||
|
|
@ -573,7 +596,7 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
|
||||
// Script tag with external path
|
||||
$source = '<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.0/js/bootstrap.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>';
|
||||
$target = '<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.0/js/bootstrap.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"><?php $this->config->context = "HTML"; ?></script>';
|
||||
$target = '<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.0/js/bootstrap.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>';
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Absolute URL
|
||||
|
|
@ -797,7 +820,7 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
]);
|
||||
$target = implode("\n", [
|
||||
"<?php if (\$this->_v2_errorExists('email', 'login')): ?>",
|
||||
"<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->message ?? '') : htmlspecialchars(\$__Context->message ?? '', \ENT_QUOTES, 'UTF-8', false); ?>",
|
||||
"<?php echo \$this->config->context === 'HTML' ? htmlspecialchars(\$__Context->message ?? '', \ENT_QUOTES, 'UTF-8', false) : \$this->_v2_escape(\$__Context->message ?? ''); ?>",
|
||||
'<?php endif; ?>',
|
||||
]);
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
|
@ -858,10 +881,10 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
'@endmobile',
|
||||
]);
|
||||
$target = implode("\n", [
|
||||
"<?php if (!\\Context::get('m')): ?>",
|
||||
'<?php if (!$this->_v2_isMobile()): ?>',
|
||||
'<p>4K or GTFO!</p>',
|
||||
'<?php endif; ?>',
|
||||
"<?php if (\\Context::get('m')): ?>",
|
||||
'<?php if ($this->_v2_isMobile()): ?>',
|
||||
'<p>USB C is the way to go~</p>',
|
||||
'<?php endif; ?>',
|
||||
]);
|
||||
|
|
@ -976,17 +999,17 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
|
||||
// Lang code with variable as name
|
||||
$source = '@lang($var->name)';
|
||||
$target = '<?php echo $this->config->context === \'JS\' ? escape_js($this->_v2_lang($__Context->var->name)) : $this->_v2_lang($__Context->var->name); ?>';
|
||||
$target = '<?php echo $this->config->context === \'HTML\' ? $this->_v2_lang($__Context->var->name) : $this->_v2_escape($this->_v2_lang($__Context->var->name)); ?>';
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Lang code with literal name and variable
|
||||
$source = "@lang('board.cmd_list_items', \$var)";
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$this->_v2_lang('board.cmd_list_items', \$__Context->var)) : \$this->_v2_lang('board.cmd_list_items', \$__Context->var); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? \$this->_v2_lang('board.cmd_list_items', \$__Context->var) : \$this->_v2_escape(\$this->_v2_lang('board.cmd_list_items', \$__Context->var)); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Lang code with class alias
|
||||
$source = "@use('Rhymix\Framework\Lang', 'Lang')\n" . '<p>@lang(Lang::getLang())</p>';
|
||||
$target = "\n" . '<p><?php echo $this->config->context === \'JS\' ? escape_js($this->_v2_lang(Rhymix\Framework\Lang::getLang())) : $this->_v2_lang(Rhymix\Framework\Lang::getLang()); ?></p>';
|
||||
$target = "\n" . '<p><?php echo $this->config->context === \'HTML\' ? $this->_v2_lang(Rhymix\Framework\Lang::getLang()) : $this->_v2_escape($this->_v2_lang(Rhymix\Framework\Lang::getLang())); ?></p>';
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Dump one variable
|
||||
|
|
@ -1001,12 +1024,17 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
|
||||
// URL
|
||||
$source = "@url(['mid' => 'foo', 'act' => 'dispBoardWrite'])";
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(getNotEncodedUrl(['mid' => 'foo', 'act' => 'dispBoardWrite'])) : getUrl(['mid' => 'foo', 'act' => 'dispBoardWrite']); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? getUrl(['mid' => 'foo', 'act' => 'dispBoardWrite']) : \$this->_v2_escape(getNotEncodedUrl(['mid' => 'foo', 'act' => 'dispBoardWrite'])); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// URL old-style with variables
|
||||
$source = "@url('', 'mid', \$mid, 'act', \$act])";
|
||||
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(getNotEncodedUrl('', 'mid', \$__Context->mid, 'act', \$__Context->act])) : getUrl('', 'mid', \$__Context->mid, 'act', \$__Context->act]); ?>";
|
||||
$target = "<?php echo \$this->config->context === 'HTML' ? getUrl('', 'mid', \$__Context->mid, 'act', \$__Context->act]) : \$this->_v2_escape(getNotEncodedUrl('', 'mid', \$__Context->mid, 'act', \$__Context->act])); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
|
||||
// Widget
|
||||
$source = "@widget('login_info', ['skin' => 'default'])";
|
||||
$target = "<?php echo \WidgetController::getInstance()->execute('login_info', ['skin' => 'default']); ?>";
|
||||
$this->assertEquals($target, $this->_parse($source));
|
||||
}
|
||||
|
||||
|
|
@ -1197,6 +1225,24 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
$this->assertStringContainsString('/tests/_data/template/css/style.scss', array_first($list)['file']);
|
||||
}
|
||||
|
||||
public function testCompileContextualEscape()
|
||||
{
|
||||
// Contextual escape
|
||||
$tmpl = new \Rhymix\Framework\Template('./tests/_data/template', 'v2contextual.html');
|
||||
$tmpl->disableCache();
|
||||
$tmpl->setVars([
|
||||
'var' => 'Hello <"world"> (\'string\') variable.jpg'
|
||||
]);
|
||||
|
||||
$executed_output = $tmpl->compile();
|
||||
//Rhymix\Framework\Storage::write(\RX_BASEDIR . 'tests/_data/template/v2contextual.executed.html', $executed_output);
|
||||
$expected = file_get_contents(\RX_BASEDIR . 'tests/_data/template/v2contextual.executed.html');
|
||||
$this->assertEquals(
|
||||
$this->_normalizeWhitespace($expected),
|
||||
$this->_normalizeWhitespace($executed_output)
|
||||
);
|
||||
}
|
||||
|
||||
public function testCompileLang()
|
||||
{
|
||||
// Lang
|
||||
|
|
@ -1295,9 +1341,10 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
*
|
||||
* @param string $source
|
||||
* @param bool $force_v2 Disable version detection
|
||||
* @param bool $remove_context_switches Remove context switches that make code difficult to read
|
||||
* @return string
|
||||
*/
|
||||
protected function _parse(string $source, bool $force_v2 = true): string
|
||||
protected function _parse(string $source, bool $force_v2 = true, bool $remove_context_switches = true): string
|
||||
{
|
||||
$tmpl = new \Rhymix\Framework\Template('./tests/_data/template', 'empty.html');
|
||||
if ($force_v2)
|
||||
|
|
@ -1309,6 +1356,13 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
|||
{
|
||||
$result = substr($result, strlen($this->prefix));
|
||||
}
|
||||
|
||||
// Remove context switches.
|
||||
if ($remove_context_switches)
|
||||
{
|
||||
$result = preg_replace('#<\?php \$this->config->context = \'[A-Z]+\'; \?>#', '', $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,8 +50,10 @@ class FunctionsTest extends \Codeception\Test\Unit
|
|||
$this->assertEquals('$user_lang->userLang1234567890', escape('$user_lang->userLang1234567890', true, false));
|
||||
$this->assertEquals('$user_lang->userLang1234567890', escape('$user_lang->userLang1234567890', true, true));
|
||||
|
||||
$this->assertEquals('expressionalertXSS', escape_css('expression:alert("XSS")'));
|
||||
$this->assertEquals('expressionalert(XSS)', escape_css('expression:alert("XSS")'));
|
||||
$this->assertEquals('#123456', escape_css('#123456'));
|
||||
$this->assertEquals('16px/160% Segoe UI, sans-serif font-style', escape_css('16px/160% Segoe UI, sans-serif; font-style'));
|
||||
$this->assertEquals('box-shadow(0 1px 2px rgba(0, 0, 0, 0.15)', escape_css('box-shadow(0 1px 2px rgba(0, 0, 0, "0.15")'));
|
||||
|
||||
$this->assertEquals('hello\\\\world', escape_js('hello\\world'));
|
||||
$this->assertEquals('\u003Cbr \/\u003E', escape_js('<br />'));
|
||||
|
|
@ -226,6 +228,8 @@ class FunctionsTest extends \Codeception\Test\Unit
|
|||
|
||||
$this->assertEquals("Weird spaces are in this string", utf8_normalize_spaces("Weird\x20spaces\xe2\x80\x80are\xe2\x80\x84in\xe2\x80\x86\xe2\x80\x8bthis\x0astring"));
|
||||
$this->assertEquals("Weird spaces are in this\nstring", utf8_normalize_spaces("Weird\x20spaces\xe2\x80\x80are\xe2\x80\x84in\xe2\x80\x86\xe2\x80\x8bthis\x0astring", true));
|
||||
$this->assertEquals("Stupid Windows\nLine Breaks", utf8_normalize_spaces("Stupid Windows \r\n Line Breaks", true));
|
||||
$this->assertEquals("Multiple\nCRLF\n\nsequences", utf8_normalize_spaces("Multiple \r\nCRLF\r\n\t\r\n sequences", true));
|
||||
$this->assertEquals("Trimmed", utf8_trim("\x20\xe2\x80\x80Trimmed\xe2\x80\x84\xe2\x80\x86\xe2\x80\x8b"));
|
||||
$this->assertEquals("Trimmed", utf8_trim("\x20\xe2\x80\x80Trimmed\x0a\x0c\x07\x09"));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue