Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Lastorder 2025-12-24 03:07:48 +00:00
commit 881b0fbac1
58 changed files with 606 additions and 200 deletions

View file

@ -3,7 +3,7 @@
/**
* RX_VERSION is the version number of the Rhymix CMS.
*/
define('RX_VERSION', '2.1.27');
define('RX_VERSION', '2.1.29');
/**
* RX_MICROTIME is the startup time of the current script, in microseconds since the Unix epoch.

View file

@ -962,7 +962,7 @@ class DB
public function getColumnInfo(string $table_name, string $column_name): ?object
{
// If column information is not found, return null.
$stmt = $this->_handle->query(sprintf("SHOW FIELDS FROM `%s` WHERE Field = '%s'", $this->addQuotes($this->_prefix . $table_name), $this->addQuotes($column_name)));
$stmt = $this->_handle->query(sprintf("SHOW FULL COLUMNS FROM `%s` WHERE Field = '%s'", $this->addQuotes($this->_prefix . $table_name), $this->addQuotes($column_name)));
$column_info = $this->fetch($stmt);
if (!$column_info)
{
@ -982,6 +982,16 @@ class DB
}
$xetype = Parsers\DBTableParser::getXEType($dbtype, $size ?: '');
// Detect the character set.
if (preg_match('/^([a-zA-Z0-9]+)/', $column_info->{'Collation'} ?? '', $matches))
{
$charset = $matches[1] === 'utf8mb3' ? 'utf8' : $matches[1];
}
else
{
$charset = null;
}
// Return the result as an object.
return (object)array(
'name' => $column_name,
@ -990,6 +1000,8 @@ class DB
'size' => $size,
'default_value' => $column_info->{'Default'},
'notnull' => strncmp($column_info->{'Null'}, 'NO', 2) == 0 ? true : false,
'charset' => $charset,
'collation' => $column_info->{'Collation'} ?: null,
);
}
@ -1100,6 +1112,7 @@ class DB
return (object)array(
'name' => $column->Key_name,
'table' => $column->Table,
'type' => $column->Index_type,
'is_unique' => $is_unique,
'columns' => $columns,
);

View file

@ -28,11 +28,11 @@ class DateTime
{
if ($format === self::FORMAT_RELATIVE)
{
return self::getRelativeTimestamp($timestamp ?: time());
return self::getRelativeTimestamp($timestamp ?? time());
}
$offset = Config::get('locale.internal_timezone') ?: date('Z', $timestamp);
return gmdate($format, ($timestamp ?: time()) + $offset);
$offset = Config::get('locale.internal_timezone') ?: date('Z', $timestamp ?? time());
return gmdate($format, ($timestamp ?? time()) + $offset);
}
/**
@ -46,7 +46,7 @@ class DateTime
{
if ($format === self::FORMAT_RELATIVE)
{
return self::getRelativeTimestamp($timestamp ?: time());
return self::getRelativeTimestamp($timestamp ?? time());
}
$timezone = self::getTimezoneForCurrentUser();
@ -55,7 +55,7 @@ class DateTime
self::$_timezones[$timezone] = new \DateTimeZone($timezone);
}
$datetime = new \DateTime();
$datetime->setTimestamp($timestamp ?: time());
$datetime->setTimestamp($timestamp ?? time());
$datetime->setTimezone(self::$_timezones[$timezone]);
return $datetime->format($format);
}
@ -123,7 +123,7 @@ class DateTime
self::$_timezones[$timezone] = new \DateTimeZone($timezone);
}
$datetime = new \DateTime();
$datetime->setTimestamp($timestamp ?: time());
$datetime->setTimestamp($timestamp ?? time());
$datetime->setTimezone(self::$_timezones[$timezone]);
return $datetime->getOffset();
}
@ -137,7 +137,7 @@ class DateTime
*/
public static function getTimezoneOffsetFromInternal(string $timezone, ?int $timestamp = null): int
{
return self::getTimezoneOffset($timezone, $timestamp ?: time()) - Config::get('locale.internal_timezone');
return self::getTimezoneOffset($timezone, $timestamp ?? time()) - Config::get('locale.internal_timezone');
}
/**
@ -192,7 +192,7 @@ class DateTime
*/
public static function getRelativeTimestamp(?int $timestamp = null): string
{
$diff = \RX_TIME - intval($timestamp ?: time());
$diff = \RX_TIME - intval($timestamp ?? time());
$langs = lang('common.time_gap');
if ($diff < 3)

View file

@ -865,7 +865,14 @@ class Template
}
}
return sprintf(' %s="%s"', $attribute, escape(implode($delimiters[$attribute], $values), false));
if (count($values))
{
return sprintf(' %s="%s"', $attribute, escape(implode($delimiters[$attribute], $values), false));
}
else
{
return '';
}
}
/**

View file

@ -156,7 +156,7 @@ class TemplateParser_v1
// if not exists default hidden tag, generate hidden tag
if ($autoform)
{
preg_match_all('/<input[^>]* name="(act|mid)"/is', $matches[2], $m2);
preg_match_all('/<(?:input|select)[^>]* name="(act|mid)"/is', $matches[2], $m2);
$missing_inputs = array_diff(['act', 'mid'], $m2[1]);
if(is_array($missing_inputs))
{

View file

@ -1084,6 +1084,37 @@ class TemplateParser_v2
*/
protected function _convertVariableScope(string $content): string
{
// Pre-escape function declarations and closures so that variables inside them are not converted.
$used_vars = [];
$function_regexp = '#\b(function(?:\s+[a-zA-Z_][a-zA-Z0-9_]*)?)' .
'(\s*)(' . self::_getRegexpForParentheses(3) . ')' .
'(\s*)(use\s*\([^()]+\))?' .
'(\s*:\s*\w+)?' .
'(\s*)(' . self::_getRegexpForCurlyBraces(8) . ')#';
$content = preg_replace_callback($function_regexp, function($match) use (&$used_vars) {
$fn = $match[1] . $match[2] . self::_escapeVars($match[3]) .
$match[4] . self::_escapeVars($match[5]) .
$match[6] . $match[7] . self::_escapeVars($match[8]);
if (str_starts_with($match[5], 'use'))
{
preg_match_all('#\$([a-zA-Z_][a-zA-Z0-9_]*)#', $match[5], $uses);
foreach ($uses[1] as $var)
{
$used_vars[$var] = true;
}
}
return $fn;
}, $content);
if (count($used_vars))
{
$prefix = ' ';
foreach ($used_vars as $var => $unused)
{
$prefix .= self::_escapeVars('$' . $var) . ' = &$__Context->' . $var . '; ';
}
$content = $prefix . $content;
}
// Replace variables that need to be enclosed in curly braces, using temporary entities to prevent double-replacement.
$content = preg_replace_callback('#(?<!\$__Context)->\$([a-zA-Z_][a-zA-Z0-9_]*)#', function($match) {
return '->' . self::_escapeCurly('{') . '$__Context->' . $match[1] . self::_escapeCurly('}');
@ -1144,6 +1175,17 @@ class TemplateParser_v2
return '\([^)(]*+(?:(?' . $position_in_regexp . ')[^)(]*)*+\)';
}
/**
* Same as above, but for curly braces.
*
* @param int $position_in_regexp
* @return string
*/
protected static function _getRegexpForCurlyBraces(int $position_in_regexp): string
{
return '\{[^}{]*+(?:(?' . $position_in_regexp . ')[^}{]*)*+\}';
}
/**
* Escape curly braces so that they will not be interpreted as echo statements.
*