mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-05-22 05:15:29 +09:00
Merge branch 'develop' into template-v2
This commit is contained in:
commit
c777b59afb
296 changed files with 2392 additions and 1676 deletions
|
|
@ -164,7 +164,10 @@ class Config
|
|||
}
|
||||
|
||||
// Remove the backup file.
|
||||
Storage::delete($backup_filename);
|
||||
if (isset($backup_filename))
|
||||
{
|
||||
Storage::delete($backup_filename);
|
||||
}
|
||||
|
||||
// Save XE-compatible config files.
|
||||
$warning = '// THIS FILE IS NOT USED IN RHYMIX.' . "\n" . '// TO MODIFY SYSTEM CONFIGURATION, EDIT config.php INSTEAD.';
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ class Debug
|
|||
);
|
||||
|
||||
self::$_remote_requests[] = $request_object;
|
||||
if ($request_object->elapsed_time && $request_object->elapsed_time >= (self::$_config['log_slow_remote_requests'] ?? 1))
|
||||
if ($request_object->elapsed_time && is_numeric($request_object->elapsed_time) && $request_object->elapsed_time >= (self::$_config['log_slow_remote_requests'] ?? 1))
|
||||
{
|
||||
self::$_slow_remote_requests[] = $request_object;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ class Session
|
|||
$_SESSION['RHYMIX']['ipaddress'] = $_SESSION['ipaddress'] = \RX_CLIENT_IP;
|
||||
$_SESSION['RHYMIX']['useragent'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
||||
$_SESSION['RHYMIX']['language'] = \Context::getLangType();
|
||||
$_SESSION['RHYMIX']['timezone'] = DateTime::getTimezoneForCurrentUser();
|
||||
// $_SESSION['RHYMIX']['timezone'] = DateTime::getTimezoneForCurrentUser();
|
||||
$_SESSION['RHYMIX']['secret'] = Security::getRandom(32, 'alnum');
|
||||
$_SESSION['RHYMIX']['domains'] = array();
|
||||
$_SESSION['RHYMIX']['tokens'] = array();
|
||||
|
|
|
|||
|
|
@ -38,6 +38,18 @@ class HTMLFilter
|
|||
'web-share' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* List of tags where data-* attributes are allowed.
|
||||
*/
|
||||
protected static $_data_allowed = array(
|
||||
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'p',
|
||||
'a', 'span', 'img', 'picture', 'b', 'i', 'strong', 'em', 'u', 's', 'sub', 'sup',
|
||||
'header', 'footer', 'nav', 'main', 'section', 'article', 'aside', 'details', 'summary',
|
||||
'ul', 'ol', 'li', 'mark', 'wbr', 'figure', 'figcaption', 'caption',
|
||||
'table', 'thead', 'tbody', 'tr', 'th', 'td', 'ins', 'del',
|
||||
'iframe', 'video', 'audio', 'source', 'track', 'blockquote', 'code',
|
||||
);
|
||||
|
||||
/**
|
||||
* Prepend a pre-processing filter.
|
||||
*
|
||||
|
|
@ -93,11 +105,6 @@ class HTMLFilter
|
|||
*/
|
||||
public static function clean(string $input, $allow_classes = false, bool $allow_editor_components = true, bool $allow_widgets = false): string
|
||||
{
|
||||
foreach (self::$_preproc as $callback)
|
||||
{
|
||||
$input = $callback($input);
|
||||
}
|
||||
|
||||
if ($allow_classes === true)
|
||||
{
|
||||
$allowed_classes = null;
|
||||
|
|
@ -119,13 +126,20 @@ class HTMLFilter
|
|||
}
|
||||
}
|
||||
|
||||
$input = self::_preprocess($input, $allow_editor_components, $allow_widgets);
|
||||
$output = self::getHTMLPurifier($allowed_classes)->purify($input);
|
||||
$output = self::_postprocess($output, $allow_editor_components, $allow_widgets);
|
||||
$purifier = self::getHTMLPurifier($allowed_classes);
|
||||
|
||||
foreach (self::$_preproc as $callback)
|
||||
{
|
||||
$input = $callback($input, $purifier, $allow_editor_components, $allow_widgets);
|
||||
}
|
||||
|
||||
$input = self::_preprocess($input, $purifier, $allow_editor_components, $allow_widgets);
|
||||
$output = $purifier->purify($input);
|
||||
$output = self::_postprocess($output, $purifier, $allow_editor_components, $allow_widgets);
|
||||
|
||||
foreach (self::$_postproc as $callback)
|
||||
{
|
||||
$output = $callback($output);
|
||||
$output = $callback($output, $purifier, $allow_editor_components, $allow_widgets);
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
|
@ -214,13 +228,6 @@ class HTMLFilter
|
|||
$config->set('Cache.SerializerPath', \RX_BASEDIR . 'files/cache/htmlpurifier');
|
||||
Storage::createDirectory(\RX_BASEDIR . 'files/cache/htmlpurifier');
|
||||
|
||||
// Modify the HTML definition to support editor components and widgets.
|
||||
$def = $config->getHTMLDefinition(true);
|
||||
$def->addAttribute('img', 'editor_component', 'Text');
|
||||
$def->addAttribute('div', 'editor_component', 'Text');
|
||||
$def->addAttribute('img', 'rx_encoded_properties', 'Text');
|
||||
$def->addAttribute('div', 'rx_encoded_properties', 'Text');
|
||||
|
||||
// Support HTML5 and CSS3.
|
||||
self::_supportHTML5($config);
|
||||
self::_supportCSS3($config);
|
||||
|
|
@ -255,6 +262,8 @@ class HTMLFilter
|
|||
$def->addElement('section', 'Block', 'Flow', 'Common');
|
||||
$def->addElement('article', 'Block', 'Flow', 'Common');
|
||||
$def->addElement('aside', 'Block', 'Flow', 'Common');
|
||||
$def->addElement('details', 'Block', 'Flow', 'Common');
|
||||
$def->addElement('summary', 'Block', 'Flow', 'Common');
|
||||
|
||||
// Add various inline tags.
|
||||
$def->addElement('s', 'Inline', 'Inline', 'Common');
|
||||
|
|
@ -313,15 +322,28 @@ class HTMLFilter
|
|||
));
|
||||
|
||||
// Support additional properties.
|
||||
$def->addAttribute('details', 'open', 'Bool');
|
||||
$def->addAttribute('i', 'aria-hidden', 'Text');
|
||||
$def->addAttribute('img', 'srcset', 'Text');
|
||||
$def->addAttribute('img', 'data-file-srl', 'Number');
|
||||
$def->addAttribute('iframe', 'allow', 'Text');
|
||||
$def->addAttribute('iframe', 'allowfullscreen', 'Bool');
|
||||
$def->addAttribute('iframe', 'referrerpolicy', 'Enum#no-referrer,no-referrer-when-downgrade,origin,origin-when-cross-origin,same-origin,strict-origin,strict-origin-when-cross-origin,unsafe-url');
|
||||
|
||||
// Support contenteditable="false" (#1710)
|
||||
$def->addAttribute('div', 'contenteditable', 'Enum#false');
|
||||
|
||||
// Support editor components and widgets.
|
||||
$def->addAttribute('img', 'data-file-srl', 'Number');
|
||||
$def->addAttribute('img', 'editor_component', 'Text');
|
||||
$def->addAttribute('div', 'editor_component', 'Text');
|
||||
$def->addAttribute('img', 'rx_encoded_properties', 'Text');
|
||||
$def->addAttribute('div', 'rx_encoded_properties', 'Text');
|
||||
|
||||
// Support encoded data-* attributes for some tags.
|
||||
foreach (self::$_data_allowed as $tag)
|
||||
{
|
||||
$def->addAttribute($tag, 'rx_encoded_datas', 'Text');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -480,17 +502,21 @@ class HTMLFilter
|
|||
* Rhymix-specific preprocessing method.
|
||||
*
|
||||
* @param string $content
|
||||
* @param \HTMLPurifier $purifier
|
||||
* @param bool $allow_editor_components (optional)
|
||||
* @param bool $allow_widgets (optional)
|
||||
* @return string
|
||||
*/
|
||||
protected static function _preprocess(string $content, bool $allow_editor_components = true, bool $allow_widgets = false): string
|
||||
protected static function _preprocess(string $content, \HTMLPurifier $purifier, bool $allow_editor_components = true, bool $allow_widgets = false): string
|
||||
{
|
||||
// Encode widget and editor component properties so that they are not removed by HTMLPurifier.
|
||||
if ($allow_editor_components || $allow_widgets)
|
||||
{
|
||||
$content = self::_encodeWidgetsAndEditorComponents($content, $allow_editor_components, $allow_widgets);
|
||||
}
|
||||
|
||||
// Encode data-* attributes.
|
||||
$content = self::_encodeDataAttributes($content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
|
@ -498,11 +524,12 @@ class HTMLFilter
|
|||
* Rhymix-specific postprocessing method.
|
||||
*
|
||||
* @param string $content
|
||||
* @param \HTMLPurifier $purifier
|
||||
* @param bool $allow_editor_components (optional)
|
||||
* @param bool $allow_widgets (optional)
|
||||
* @return string
|
||||
*/
|
||||
protected static function _postprocess(string $content, bool $allow_editor_components = true, bool $allow_widgets = false): string
|
||||
protected static function _postprocess(string $content, \HTMLPurifier $purifier, bool $allow_editor_components = true, bool $allow_widgets = false): string
|
||||
{
|
||||
// Define acts to allow and deny.
|
||||
$allow_acts = array('procFileDownload');
|
||||
|
|
@ -558,6 +585,9 @@ class HTMLFilter
|
|||
|
||||
// Restore widget and editor component properties.
|
||||
$content = self::_decodeWidgetsAndEditorComponents($content, $allow_editor_components, $allow_widgets);
|
||||
|
||||
// Restore data-* attributes.
|
||||
$content = self::_decodeDataAttributes($content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
|
@ -598,7 +628,7 @@ class HTMLFilter
|
|||
{
|
||||
return $attr[0];
|
||||
}
|
||||
$attrval = utf8_normalize_spaces(utf8_clean(html_entity_decode($attr[2])));
|
||||
$attrval = trim(utf8_normalize_spaces(utf8_clean(html_entity_decode($attr[2]))));
|
||||
if (preg_match('/^javascript:/i', preg_replace('/\s+/', '', $attrval)))
|
||||
{
|
||||
return '';
|
||||
|
|
@ -653,7 +683,69 @@ class HTMLFilter
|
|||
}
|
||||
foreach ($decoded_properties as $key => $val)
|
||||
{
|
||||
$attrs[] = $key . '="' . htmlspecialchars($val) . '"';
|
||||
$attrs[] = $key . '="' . htmlspecialchars($val, ENT_QUOTES, 'UTF-8') . '"';
|
||||
}
|
||||
return str_replace($match[3], ' ' . implode(' ', $attrs), $match[0]);
|
||||
}, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode data-* attributes so that they will survive being passed through HTMLPurifier.
|
||||
*
|
||||
* @param string $content
|
||||
* @return string
|
||||
*/
|
||||
protected static function _encodeDataAttributes(string $content): string
|
||||
{
|
||||
$tags = implode('|', self::$_data_allowed);
|
||||
return preg_replace_callback('!<(' . $tags . ')\s([^>]+)>!i', function($match) {
|
||||
$attrs = array();
|
||||
$html = preg_replace_callback('!\s(data-[a-zA-Z0-9_-]+)="([^"]*)"!', function($attr) use(&$attrs) {
|
||||
$attrkey = strtolower($attr[1]);
|
||||
$attrval = trim(utf8_normalize_spaces(utf8_clean(html_entity_decode($attr[2]))));
|
||||
if (preg_match('/^(data-file-srl)$/', $attrkey))
|
||||
{
|
||||
return $attr[0];
|
||||
}
|
||||
if (preg_match('/^javascript:/i', preg_replace('/\s+/', '', $attrval)))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
$attrs[$attrkey] = $attrval;
|
||||
return '';
|
||||
}, $match[0]);
|
||||
$encoded_datas = base64_encode(json_encode($attrs));
|
||||
$encoded_datas = $encoded_datas . ':' . Security::createSignature($encoded_datas);
|
||||
return rtrim($html, ' />') . ' rx_encoded_datas="' . $encoded_datas . '"' . (preg_match('!/>$!', $html) ? ' />' : '>');
|
||||
}, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode data-* attributes after processing.
|
||||
*
|
||||
* @param string $content
|
||||
* @param bool $allow_editor_components (optional)
|
||||
* @param bool $allow_widgets (optional)
|
||||
* @return string
|
||||
*/
|
||||
protected static function _decodeDataAttributes(string $content): string
|
||||
{
|
||||
$tags = implode('|', self::$_data_allowed);
|
||||
return preg_replace_callback('!<(' . $tags . ')([^>]*)(\srx_encoded_datas="([^"]+)")!i', function($match) {
|
||||
$attrs = array();
|
||||
list($encoded_datas, $signature) = explode(':', $match[4]);
|
||||
if (!Security::verifySignature($encoded_datas, $signature))
|
||||
{
|
||||
return str_replace($match[3], '', $match[0]);
|
||||
}
|
||||
$encoded_datas = json_decode(base64_decode($encoded_datas));
|
||||
if (!$encoded_datas)
|
||||
{
|
||||
return str_replace($match[3], '', $match[0]);
|
||||
}
|
||||
foreach ($encoded_datas as $key => $val)
|
||||
{
|
||||
$attrs[] = $key . '="' . htmlspecialchars($val, ENT_QUOTES, 'UTF-8') . '"';
|
||||
}
|
||||
return str_replace($match[3], ' ' . implode(' ', $attrs), $match[0]);
|
||||
}, $content);
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ class DBQueryParser extends BaseParser
|
|||
{
|
||||
$group = new DBQuery\ConditionGroup;
|
||||
$group->conditions = self::_parseConditions($tag);
|
||||
$group->pipe = strtoupper($attribs['pipe'] ?? null) ?: 'AND';
|
||||
$group->pipe = strtoupper($attribs['pipe'] ?? '') ?: 'AND';
|
||||
$group->ifvar = $attribs['if'] ?? null;
|
||||
$result[] = $group;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class VariableBase
|
|||
{
|
||||
if ($this->not_null)
|
||||
{
|
||||
throw new \Rhymix\Framework\Exceptions\QueryError('Variable ' . $this->var . ' for column ' . $this->column . ' must not be null');
|
||||
throw new \Rhymix\Framework\Exceptions\QueryError('Variable ' . $this->var . ' for column ' . ($this->column ?? ($this->name ?? 'unknown')) . ' must not be null');
|
||||
}
|
||||
if ($this instanceof Condition && in_array($this->operation, ['equal', 'notequal', 'not_equal']))
|
||||
{
|
||||
|
|
@ -89,7 +89,7 @@ class VariableBase
|
|||
}
|
||||
elseif ($this->not_null)
|
||||
{
|
||||
throw new \Rhymix\Framework\Exceptions\QueryError('Variable ' . $this->var . ' for column ' . ($this->column ?? 'unknown') . ' is not set');
|
||||
throw new \Rhymix\Framework\Exceptions\QueryError('Variable ' . $this->var . ' for column ' . ($this->column ?? ($this->name ?? 'unknown')) . ' is not set');
|
||||
}
|
||||
elseif (!in_array($this->operation, ['null', 'notnull', 'not_null']))
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue