Compare commits

...

24 commits

Author SHA1 Message Date
Lastorder
ef9967fc1d
Merge branch 'rhymix:master' into master 2025-08-27 17:08:18 +09:00
Kijin Sung
70e04a1dc5 Fix infamous "내용 값은 필수입니다" in legacy sketchbook skin 2025-08-25 23:55:00 +09:00
Kijin Sung
771dbfe114 Experimental method to clear APC cache from PHP-CLI #2554 #1943 2025-08-24 22:16:39 +09:00
Kijin Sung
e0033ac2fc Add select box to filter by module in document, comment, and file list 2025-08-24 21:35:50 +09:00
Kijin Sung
02c2f343cd Fix grant being reset to "manager only" in menu settings if the default value is "manager" 2025-08-24 21:11:30 +09:00
Kijin Sung
0d03d2a3dd Remove unnecessary information from password reset email #2594 2025-08-22 00:09:35 +09:00
Kijin Sung
6d95dd9fc8 Remove unnecessary logout.html and related XML filter #2593 2025-08-22 00:03:12 +09:00
Kijin Sung
f1b2b4eaec Fix double escape of comment summary 2025-08-21 13:43:14 +09:00
Kijin Sung
23190bd2f5 Remove all use of global variables as debug timers 2025-08-20 00:34:57 +09:00
Kijin Sung
f91bd86fb1 Consolidate a few timers into an array in the Debug class 2025-08-20 00:25:20 +09:00
Kijin Sung
e7d14be6bb Fix inappropriate quoting of "distinct" in XML query
https://rhymix.org/qna/1914711
2025-08-19 00:22:02 +09:00
Kijin Sung
6917a76726 Apply x_full-width to skin and layout config items of type=textarea 2025-08-18 22:29:47 +09:00
Kijin Sung
451d0b95ac Disable all conversion inside verbatim section of template v2 2025-08-18 22:24:48 +09:00
Kijin Sung
f7543e4c9a In template v2, process escape filters before other filters 2025-08-18 22:09:31 +09:00
Kijin Sung
3b2fa4208d Display error count in debug panel for ajax requests 2025-08-13 21:31:17 +09:00
Kijin Sung
4497b68366 Update dependencies 2025-08-13 21:19:10 +09:00
Kijin Sung
fad0bc9153
Merge pull request #2592 from rhymix/dependabot/composer/common/enshrined/svg-sanitize-0.22.0
Bump enshrined/svg-sanitize from 0.21.0 to 0.22.0 in /common
2025-08-13 21:16:48 +09:00
Kijin Sung
08fc4d72d9 Fix incorrect error message when a document/comment is voted/blamed already #2590 2025-08-13 21:15:11 +09:00
Kijin Sung
316cfc43b0 Fix type error if extra_vars does not unserialize into an object #2591 2025-08-13 21:05:31 +09:00
Kijin Sung
b00f956d6b Fix incorrect XML header in some environments 2025-08-13 21:03:03 +09:00
dependabot[bot]
ac90dcf16c
Bump enshrined/svg-sanitize from 0.21.0 to 0.22.0 in /common
Bumps [enshrined/svg-sanitize](https://github.com/darylldoyle/svg-sanitizer) from 0.21.0 to 0.22.0.
- [Release notes](https://github.com/darylldoyle/svg-sanitizer/releases)
- [Commits](https://github.com/darylldoyle/svg-sanitizer/compare/0.21.0...0.22.0)

---
updated-dependencies:
- dependency-name: enshrined/svg-sanitize
  dependency-version: 0.22.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-13 04:52:29 +00:00
Kijin Sung
36d7dcebcd Fix double escaping of title when cut_str() is used on it 2025-08-07 01:32:22 +09:00
Kijin Sung
a0b045b087 Hide countries with no calling code assigned 2025-08-07 01:32:00 +09:00
Kijin Sung
bcf81bce4d Prevent infinite addition of sequence numbers to $_SESSION 2025-08-03 22:33:51 +09:00
81 changed files with 923 additions and 726 deletions

View file

@ -183,7 +183,7 @@ class HTMLDisplayHandler
$pathInfo = pathinfo($layout_file);
$onlyLayoutFile = $pathInfo['filename'];
$GLOBALS['__layout_compile_elapsed__'] = microtime(true) - $start;
Rhymix\Framework\Debug::addTime('layout', microtime(true) - $start);
}
}
@ -297,7 +297,7 @@ class HTMLDisplayHandler
$output = preg_replace_callback('@<textarea[^>]*\sname="' . $keys . '".+</textarea>@isU', array(&$this, '_preserveTextAreaValue'), $output);
}
$GLOBALS['__trans_content_elapsed__'] = microtime(true) - $start;
Rhymix\Framework\Debug::addTime('trans_content', microtime(true) - $start);
// Remove unnecessary information
$output = preg_replace('/member\_\-([0-9]+)/s', 'member_0', $output);

119
common/composer.lock generated
View file

@ -64,16 +64,16 @@
},
{
"name": "composer/ca-bundle",
"version": "1.5.5",
"version": "1.5.7",
"source": {
"type": "git",
"url": "https://github.com/composer/ca-bundle.git",
"reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6"
"reference": "d665d22c417056996c59019579f1967dfe5c1e82"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/08c50d5ec4c6ced7d0271d2862dec8c1033283e6",
"reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/d665d22c417056996c59019579f1967dfe5c1e82",
"reference": "d665d22c417056996c59019579f1967dfe5c1e82",
"shasum": ""
},
"require": {
@ -120,7 +120,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/ca-bundle/issues",
"source": "https://github.com/composer/ca-bundle/tree/1.5.5"
"source": "https://github.com/composer/ca-bundle/tree/1.5.7"
},
"funding": [
{
@ -136,7 +136,7 @@
"type": "tidelift"
}
],
"time": "2025-01-08T16:17:16+00:00"
"time": "2025-05-26T15:08:54+00:00"
},
{
"name": "coolsms/php-sdk",
@ -194,6 +194,7 @@
"issues": "https://github.com/coolsms/php-sdk/issues",
"source": "https://github.com/coolsms/php-sdk/tree/master"
},
"abandoned": true,
"time": "2016-09-02T03:28:39+00:00"
},
{
@ -341,16 +342,16 @@
},
{
"name": "enshrined/svg-sanitize",
"version": "0.21.0",
"version": "0.22.0",
"source": {
"type": "git",
"url": "https://github.com/darylldoyle/svg-sanitizer.git",
"reference": "5e477468fac5c5ce933dce53af3e8e4e58dcccc9"
"reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/5e477468fac5c5ce933dce53af3e8e4e58dcccc9",
"reference": "5e477468fac5c5ce933dce53af3e8e4e58dcccc9",
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/0afa95ea74be155a7bcd6c6fb60c276c39984500",
"reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500",
"shasum": ""
},
"require": {
@ -380,9 +381,9 @@
"description": "An SVG sanitizer for PHP",
"support": {
"issues": "https://github.com/darylldoyle/svg-sanitizer/issues",
"source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.21.0"
"source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.22.0"
},
"time": "2025-01-13T09:32:25+00:00"
"time": "2025-08-12T10:13:48+00:00"
},
{
"name": "ezyang/htmlpurifier",
@ -568,16 +569,16 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "7.9.2",
"version": "7.9.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "d281ed313b989f213357e3be1a179f02196ac99b"
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b",
"reference": "d281ed313b989f213357e3be1a179f02196ac99b",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"shasum": ""
},
"require": {
@ -674,7 +675,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.9.2"
"source": "https://github.com/guzzle/guzzle/tree/7.9.3"
},
"funding": [
{
@ -690,20 +691,20 @@
"type": "tidelift"
}
],
"time": "2024-07-24T11:22:20+00:00"
"time": "2025-03-27T13:37:11+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.0.4",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455"
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
"url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
"shasum": ""
},
"require": {
@ -757,7 +758,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.0.4"
"source": "https://github.com/guzzle/promises/tree/2.2.0"
},
"funding": [
{
@ -773,20 +774,20 @@
"type": "tidelift"
}
],
"time": "2024-10-17T10:06:22+00:00"
"time": "2025-03-27T13:27:01+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.7.0",
"version": "2.7.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"shasum": ""
},
"require": {
@ -873,7 +874,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.7.0"
"source": "https://github.com/guzzle/psr7/tree/2.7.1"
},
"funding": [
{
@ -889,7 +890,7 @@
"type": "tidelift"
}
],
"time": "2024-07-18T11:15:46+00:00"
"time": "2025-03-27T12:30:47+00:00"
},
{
"name": "jbbcode/jbbcode",
@ -1083,16 +1084,16 @@
},
{
"name": "matthiasmullie/minify",
"version": "1.3.73",
"version": "1.3.75",
"source": {
"type": "git",
"url": "https://github.com/matthiasmullie/minify.git",
"reference": "cb7a9297b4ab070909cefade30ee95054d4ae87a"
"reference": "76ba4a5f555fd7bf4aa408af608e991569076671"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/cb7a9297b4ab070909cefade30ee95054d4ae87a",
"reference": "cb7a9297b4ab070909cefade30ee95054d4ae87a",
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/76ba4a5f555fd7bf4aa408af608e991569076671",
"reference": "76ba4a5f555fd7bf4aa408af608e991569076671",
"shasum": ""
},
"require": {
@ -1103,8 +1104,7 @@
"require-dev": {
"friendsofphp/php-cs-fixer": ">=2.0",
"matthiasmullie/scrapbook": ">=1.3",
"phpunit/phpunit": ">=4.8",
"squizlabs/php_codesniffer": ">=3.0"
"phpunit/phpunit": ">=4.8"
},
"suggest": {
"psr/cache-implementation": "Cache implementation to use with Minify::cache"
@ -1142,7 +1142,7 @@
],
"support": {
"issues": "https://github.com/matthiasmullie/minify/issues",
"source": "https://github.com/matthiasmullie/minify/tree/1.3.73"
"source": "https://github.com/matthiasmullie/minify/tree/1.3.75"
},
"funding": [
{
@ -1150,7 +1150,7 @@
"type": "github"
}
],
"time": "2024-03-15T10:27:10+00:00"
"time": "2025-06-25T09:56:19+00:00"
},
{
"name": "matthiasmullie/path-converter",
@ -1850,16 +1850,16 @@
},
{
"name": "symfony/polyfill-iconv",
"version": "v1.31.0",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git",
"reference": "48becf00c920479ca2e910c22a5a39e5d47ca956"
"reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956",
"reference": "48becf00c920479ca2e910c22a5a39e5d47ca956",
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/5f3b930437ae03ae5dff61269024d8ea1b3774aa",
"reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa",
"shasum": ""
},
"require": {
@ -1910,7 +1910,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-iconv/tree/v1.32.0"
},
"funding": [
{
@ -1926,20 +1926,20 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-09-17T14:58:18+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.31.0",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773"
"reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773",
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3",
"reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3",
"shasum": ""
},
"require": {
@ -1993,7 +1993,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0"
},
"funding": [
{
@ -2009,11 +2009,11 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-09-10T14:38:51+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.31.0",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@ -2074,7 +2074,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
},
"funding": [
{
@ -2094,19 +2094,20 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.31.0",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": ">=7.2"
},
"provide": {
@ -2154,7 +2155,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
},
"funding": [
{
@ -2170,7 +2171,7 @@
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2024-12-23T08:48:59+00:00"
},
{
"name": "true/punycode",
@ -2243,6 +2244,6 @@
"ext-pcre": "*",
"ext-xml": "*"
},
"platform-dev": [],
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View file

@ -294,6 +294,16 @@ a img {
font-weight: bold;
margin: 0;
padding: 0;
.error_count {
display: inline-block;
margin-left: 6px;
border-radius: 4px;
padding: 2px 6px;
font-size: 12px;
line-height: 12px;
background: #f44336;
color: #ffffff;
}
}
}
.debug_page_collapse {

View file

@ -239,6 +239,10 @@ class Cache
{
if (self::$_driver !== null)
{
if (self::$_driver instanceof Drivers\Cache\APC && \PHP_SAPI === 'cli')
{
self::sendClearRequest([$key]);
}
return self::$_driver->delete(self::getRealKey($key)) ? true : false;
}
else
@ -323,6 +327,10 @@ class Cache
{
if (self::$_driver !== null)
{
if (self::$_driver instanceof Drivers\Cache\APC && \PHP_SAPI === 'cli')
{
self::sendClearRequest([$group_name . ':*']);
}
$success = self::$_driver->incr(self::$_prefix . $group_name . '#version', 1) ? true : false;
unset(self::$_group_versions[$group_name]);
return $success;
@ -344,6 +352,10 @@ class Cache
{
if (self::$_driver !== null)
{
if (self::$_driver instanceof Drivers\Cache\APC && \PHP_SAPI === 'cli')
{
self::sendClearRequest(['*']);
}
return self::$_driver->clear() ? true : false;
}
else
@ -396,4 +408,27 @@ class Cache
return self::$_prefix . $key;
}
/**
* Send a web request to clear the cache.
*
* @param array $keys
* @return void
*/
public static function sendClearRequest(array $keys): void
{
if (!$keys)
{
return;
}
$keystring = implode('|', $keys);
$signature = Security::createSignature($keystring);
HTTP::post(\Context::getRequestUri(), [
'module' => 'module',
'act' => 'procModuleClearCache',
'keys' => $keys,
'signature' => $signature,
]);
}
}

View file

@ -23,8 +23,19 @@ class Debug
protected static $_slow_widgets = array();
protected static $_remote_requests = array();
protected static $_slow_remote_requests = array();
protected static $_session_time = 0;
protected static $_query_time = 0;
/**
* Store timers here.
*/
protected static $_timers = [
'query' => 0,
'session' => 0,
'remote' => 0,
'layout' => 0,
'widget' => 0,
'template' => 0,
'trans_content' => 0,
];
/**
* Enable log collection.
@ -227,8 +238,10 @@ class Debug
self::$_slow_widgets = array();
self::$_remote_requests = array();
self::$_slow_remote_requests = array();
self::$_session_time = 0;
self::$_query_time = 0;
foreach (self::$_timers as $key => $val)
{
self::$_timers[$key] = 0;
}
}
/**
@ -244,14 +257,22 @@ class Debug
}
/**
* Add session start time.
* Add time to a timer variable.
*
* @param float $session_start_time
* @param string $type
* @param float $time
* @return void
*/
public static function addSessionStartTime(float $session_start_time): void
public static function addTime(string $type, float $time): void
{
self::$_session_time += $session_start_time;
if (isset(self::$_timers[$type]))
{
self::$_timers[$type] += $time;
}
else
{
self::$_timers[$type] = $time;
}
}
/**
@ -449,7 +470,7 @@ class Debug
}
// Record query time.
self::$_query_time += $query_object->query_time;
self::$_timers['query'] += $query_object->query_time;
// Add the query to the error log if the result wasn't successful.
if ($query['result'] === 'error')
@ -560,6 +581,8 @@ class Debug
);
self::$_widgets[] = $widget_object;
self::$_timers['widget'] += $widget_object->widget_time;
if ($widget_object->widget_time && $widget_object->widget_time >= (self::$_config['log_slow_widgets'] ?? 1))
{
self::$_slow_widgets[] = $widget_object;
@ -597,12 +620,7 @@ class Debug
);
self::$_remote_requests[] = $request_object;
if (!isset($GLOBALS['__remote_request_elapsed__']))
{
$GLOBALS['__remote_request_elapsed__'] = 0;
}
$GLOBALS['__remote_request_elapsed__'] += $request_object->elapsed_time;
self::$_timers['remote'] += $request_object->elapsed_time;
if ($request_object->elapsed_time && is_numeric($request_object->elapsed_time) && $request_object->elapsed_time >= (self::$_config['log_slow_remote_requests'] ?? 1))
{
@ -890,15 +908,14 @@ class Debug
'memory' => memory_get_peak_usage(),
'timing' => (object)array(
'total' => sprintf('%0.4f sec', microtime(true) - \RX_MICROTIME),
'db_query' => sprintf('%0.4f sec (count: %d)', self::$_query_time, count(self::$_queries)),
'db_class' => sprintf('%0.4f sec', max(0, $db->getTotalElapsedTime() - self::$_query_time)),
'layout' => sprintf('%0.4f sec', $GLOBALS['__layout_compile_elapsed__'] ?? 0),
'widget' => sprintf('%0.4f sec', $GLOBALS['__widget_excute_elapsed__'] ?? 0),
'remote' => sprintf('%0.4f sec', $GLOBALS['__remote_request_elapsed__'] ?? 0),
'session' => sprintf('%0.4f sec', self::$_session_time),
'xmlparse' => sprintf('%0.4f sec', $GLOBALS['__xmlparse_elapsed__'] ?? 0),
'template' => sprintf('%0.4f sec (count: %d)', $GLOBALS['__template_elapsed__'] ?? 0, $GLOBALS['__TemplateHandlerCalled__'] ?? 0),
'trans' => sprintf('%0.4f sec', $GLOBALS['__trans_content_elapsed__'] ?? 0),
'db_query' => sprintf('%0.4f sec (count: %d)', self::$_timers['query'], count(self::$_queries)),
'db_class' => sprintf('%0.4f sec', max(0, $db->getTotalElapsedTime() - self::$_timers['query'])),
'session' => sprintf('%0.4f sec', self::$_timers['session']),
'remote' => sprintf('%0.4f sec', self::$_timers['remote']),
'layout' => sprintf('%0.4f sec', self::$_timers['layout']),
'widget' => sprintf('%0.4f sec', self::$_timers['widget']),
'template' => sprintf('%0.4f sec', self::$_timers['template']),
'trans' => sprintf('%0.4f sec', self::$_timers['trans_content']),
),
'entries' => array_values(self::$_entries),
'errors' => array_values(self::$_errors),

View file

@ -324,56 +324,13 @@ class HTTP
Debug::addRemoteRequest($log);
};
}
else
{
$settings['on_stats'] = function($stats) {
Debug::addTime('remote', $stats->getTransferTime());
};
}
return $settings;
}
/**
* Record a request with the Debug class.
*
* @param string $url
* @param int $status_code
* @param float $elapsed_time
* @return void
*/
protected static function _debug(string $url, int $status_code = 0, float $elapsed_time = 0): void
{
if (!isset($GLOBALS['__remote_request_elapsed__']))
{
$GLOBALS['__remote_request_elapsed__'] = 0;
}
$GLOBALS['__remote_request_elapsed__'] += $elapsed_time;
if (Debug::isEnabledForCurrentUser())
{
$log = array();
$log['url'] = $url;
$log['status'] = $status_code;
$log['elapsed_time'] = $elapsed_time;
$log['called_file'] = $log['called_line'] = $log['called_method'] = null;
$log['backtrace'] = [];
if (in_array('slow_remote_requests', config('debug.display_content')))
{
$bt = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
foreach ($bt as $no => $call)
{
if($call['file'] !== __FILE__ && $call['file'] !== \RX_BASEDIR . 'classes/file/FileHandler.class.php')
{
$log['called_file'] = $bt[$no]['file'];
$log['called_line'] = $bt[$no]['line'];
$next = $no + 1;
if (isset($bt[$next]))
{
$log['called_method'] = $bt[$next]['class'].$bt[$next]['type'].$bt[$next]['function'];
$log['backtrace'] = array_slice($bt, $next, 1);
}
break;
}
}
}
}
}
}

View file

@ -100,7 +100,7 @@ class Session
trigger_error('Session cannot be started', \E_USER_WARNING);
return false;
}
Debug::addSessionStartTime(microtime(true) - $session_start_time);
Debug::addTime('session', microtime(true) - $session_start_time);
// Mark the session as started.
self::$_started = true;

View file

@ -378,13 +378,7 @@ class Template
$output = $this->execute();
// Record the time elapsed.
$elapsed_time = microtime(true) - $start;
if (!isset($GLOBALS['__template_elapsed__']))
{
$GLOBALS['__template_elapsed__'] = 0;
}
$GLOBALS['__template_elapsed__'] += $elapsed_time;
Debug::addTime('template', microtime(true) - $start);
return $output;
}

View file

@ -738,10 +738,11 @@ class Query extends VariableBase
*/
public static function quoteName(string $column_name): string
{
return preg_replace_callback('/[a-z][a-z0-9_.*]*(?!\\()\b/i', function($m) {
$exceptions = ['*' => true, 'DISTINCT' => true, 'distinct' => true];
return preg_replace_callback('/[a-z][a-z0-9_.*]*(?!\\()\b/i', function($m) use($exceptions) {
$columns = explode('.', $m[0]);
$columns = array_map(function($str) {
return $str === '*' ? $str : ('`' . $str . '`');
$columns = array_map(function($str) use($exceptions) {
return isset($exceptions[$str]) ? $str : ('`' . $str . '`');
}, $columns);
return implode('.', $columns);
}, $column_name);

View file

@ -138,9 +138,9 @@ class TemplateParser_v2
// Apply conversions.
$content = $this->_addContextSwitches($content);
$content = $this->_removeComments($content);
$content = $this->_convertVerbatimSections($content);
$content = $this->_convertRelativePaths($content);
$content = $this->_convertPHPSections($content);
$content = $this->_convertVerbatimSections($content);
$content = $this->_convertFragments($content);
$content = $this->_convertClassAliases($content);
$content = $this->_convertIncludes($content);
@ -872,7 +872,16 @@ class TemplateParser_v2
$str = $this->_escapeCurly($str);
$str = $this->_convertVariableScope($str);
// Apply filters.
// Process the escape option first.
foreach ($filters as $filter)
{
if (in_array($filter, ['autoescape', 'autolang', 'escape', 'noescape']))
{
$escape_option = $filter;
}
}
// Apply other filters.
foreach ($filters as $filter)
{
// Separate the filter option from the filter name.
@ -891,14 +900,13 @@ class TemplateParser_v2
}
}
// Apply each filter.
// Apply filters.
switch ($filter)
{
case 'autoescape':
case 'autolang':
case 'escape':
case 'noescape':
$escape_option = $filter;
break;
case 'escapejs':
case 'js':

View file

@ -234,6 +234,7 @@ $(function() {
// If there are errors, turn the button text red.
if (data.errors && data.errors.length) {
button_link.addClass("has_errors");
page_header.find('h3').append($('<span class="error_count"></span>').text(data.errors.length));
}
};

View file

@ -244,6 +244,10 @@ function setUserSequence($seq): void
}
$seq = intval($seq);
$_SESSION['seq'][$seq] = $seq;
if (count($_SESSION['seq']) > 1000)
{
$_SESSION['seq'] = array_slice($_SESSION['seq'], 600, null, true);
}
}
/**
@ -503,7 +507,7 @@ function cut_str($string, $cut_size = 0, $tail = '...'): string
{
$GLOBALS['use_mb_strimwidth'] = TRUE;
$string = html_entity_decode($string);
return escape(mb_strimwidth($string, 0, $cut_size + 4, $tail, 'utf-8'));
return escape(mb_strimwidth($string, 0, $cut_size + 4, $tail, 'utf-8'), false);
}
$chars = array(12, 4, 3, 5, 7, 7, 11, 8, 4, 5, 5, 6, 6, 4, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 4, 8, 6, 8, 6, 10, 8, 8, 9, 8, 8, 7, 9, 8, 3, 6, 7, 7, 11, 8, 9, 8, 9, 8, 8, 7, 8, 8, 10, 8, 8, 8, 6, 11, 6, 6, 6, 4, 7, 7, 7, 7, 7, 3, 7, 7, 3, 3, 6, 3, 9, 7, 7, 7, 7, 4, 7, 3, 7, 6, 10, 6, 6, 7, 6, 6, 6, 9);

View file

@ -17,11 +17,10 @@ Page Generation Time
Total Time: <?php echo $data->timing->total . "\n"; ?>
DB Query Time: <?php echo $data->timing->db_query . "\n"; ?>
DB Processing Time: <?php echo $data->timing->db_class . "\n"; ?>
Session Lock Wait Time: <?php echo $data->timing->session . "\n"; ?>
Remote Request Time: <?php echo $data->timing->remote . "\n"; ?>
Layout Processing Time: <?php echo $data->timing->layout . "\n"; ?>
Widget Processing Time: <?php echo $data->timing->widget . "\n"; ?>
Remote Request Time: <?php echo $data->timing->remote . "\n"; ?>
Session Lock Wait Time: <?php echo $data->timing->session . "\n"; ?>
XML Parsing Time: <?php echo $data->timing->xmlparse . "\n"; ?>
Template Compile Time: <?php echo $data->timing->template . "\n"; ?>
Content Transform Time: <?php echo $data->timing->trans . "\n"; ?>

View file

@ -14,10 +14,7 @@ if (PHP_VERSION_ID < 50600) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
throw new RuntimeException($err);
}
require_once __DIR__ . '/composer/autoload_real.php';

View file

@ -26,12 +26,23 @@ use Composer\Semver\VersionParser;
*/
class InstalledVersions
{
/**
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
* @internal
*/
private static $selfDir = null;
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool
*/
private static $installedIsLocalDir;
/**
* @var bool|null
*/
@ -309,6 +320,24 @@ class InstalledVersions
{
self::$installed = $data;
self::$installedByVendor = array();
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
// so we have to assume it does not, and that may result in duplicate data being returned when listing
// all installed packages for example
self::$installedIsLocalDir = false;
}
/**
* @return string
*/
private static function getSelfDir()
{
if (self::$selfDir === null) {
self::$selfDir = strtr(__DIR__, '\\', '/');
}
return self::$selfDir;
}
/**
@ -322,19 +351,27 @@ class InstalledVersions
}
$installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = self::getSelfDir();
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
$installed[] = self::$installedByVendor[$vendorDir] = $required;
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
self::$installedIsLocalDir = true;
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}
@ -350,7 +387,7 @@ class InstalledVersions
}
}
if (self::$installed !== array()) {
if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}

View file

@ -510,6 +510,7 @@ return array(
'MatthiasMullie\\Minify\\Exceptions\\BasicException' => $vendorDir . '/matthiasmullie/minify/src/Exceptions/BasicException.php',
'MatthiasMullie\\Minify\\Exceptions\\FileImportException' => $vendorDir . '/matthiasmullie/minify/src/Exceptions/FileImportException.php',
'MatthiasMullie\\Minify\\Exceptions\\IOException' => $vendorDir . '/matthiasmullie/minify/src/Exceptions/IOException.php',
'MatthiasMullie\\Minify\\Exceptions\\PatternMatchException' => $vendorDir . '/matthiasmullie/minify/src/Exceptions/PatternMatchException.php',
'MatthiasMullie\\Minify\\JS' => $vendorDir . '/matthiasmullie/minify/src/JS.php',
'MatthiasMullie\\Minify\\Minify' => $vendorDir . '/matthiasmullie/minify/src/Minify.php',
'MatthiasMullie\\PathConverter\\Converter' => $vendorDir . '/matthiasmullie/path-converter/src/Converter.php',

View file

@ -716,6 +716,7 @@ class ComposerStaticInit1e37ff09eb6590c7436f139ffd9070de
'MatthiasMullie\\Minify\\Exceptions\\BasicException' => __DIR__ . '/..' . '/matthiasmullie/minify/src/Exceptions/BasicException.php',
'MatthiasMullie\\Minify\\Exceptions\\FileImportException' => __DIR__ . '/..' . '/matthiasmullie/minify/src/Exceptions/FileImportException.php',
'MatthiasMullie\\Minify\\Exceptions\\IOException' => __DIR__ . '/..' . '/matthiasmullie/minify/src/Exceptions/IOException.php',
'MatthiasMullie\\Minify\\Exceptions\\PatternMatchException' => __DIR__ . '/..' . '/matthiasmullie/minify/src/Exceptions/PatternMatchException.php',
'MatthiasMullie\\Minify\\JS' => __DIR__ . '/..' . '/matthiasmullie/minify/src/JS.php',
'MatthiasMullie\\Minify\\Minify' => __DIR__ . '/..' . '/matthiasmullie/minify/src/Minify.php',
'MatthiasMullie\\PathConverter\\Converter' => __DIR__ . '/..' . '/matthiasmullie/path-converter/src/Converter.php',

View file

@ -1,14 +1,14 @@
##
## Bundle of CA Root Certificates
##
## Certificate data from Mozilla as of: Tue Dec 31 04:12:05 2024 GMT
## Certificate data from Mozilla as of: Tue May 20 03:12:02 2025 GMT
##
## Find updated versions here: https://curl.se/docs/caextract.html
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
## file (certdata.txt). This file can be found in the mozilla source tree:
## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
## https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt
##
## It contains the certificates in PEM format and therefore
## can be directly used with curl / libcurl / php_curl, or with
@ -16,76 +16,10 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.29.
## SHA256: c99d6d3f8d3d4e47719ba2b648992f5b58b150128d3aca3c05c566d8dc98e116
## SHA256: 8944ec6b572b577daee4fc681a425881f841ec2660e4cb5f0eee727f84620697
##
GlobalSign Root CA
==================
-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----
Entrust.net Premium 2048 Secure Server CA
=========================================
-----BEGIN CERTIFICATE-----
MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
-----END CERTIFICATE-----
Baltimore CyberTrust Root
=========================
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
-----END CERTIFICATE-----
Entrust Root Certification Authority
====================================
-----BEGIN CERTIFICATE-----
@ -112,30 +46,6 @@ W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
-----END CERTIFICATE-----
Comodo AAA Services root
========================
-----BEGIN CERTIFICATE-----
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----
QuoVadis Root CA 2
==================
-----BEGIN CERTIFICATE-----
@ -202,78 +112,6 @@ vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
-----END CERTIFICATE-----
XRamp Global CA Root
====================
-----BEGIN CERTIFICATE-----
MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
-----END CERTIFICATE-----
Go Daddy Class 2 CA
===================
-----BEGIN CERTIFICATE-----
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
vZ8=
-----END CERTIFICATE-----
Starfield Class 2 CA
====================
-----BEGIN CERTIFICATE-----
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
QBFGmh95DmK/D5fs4C8fF5Q=
-----END CERTIFICATE-----
DigiCert Assured ID Root CA
===========================
-----BEGIN CERTIFICATE-----
@ -371,37 +209,6 @@ NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj
viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
-----END CERTIFICATE-----
SwissSign Silver CA - G2
========================
-----BEGIN CERTIFICATE-----
MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT
BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X
DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3
aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG
9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644
N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm
+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH
6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu
MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h
qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5
FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs
ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc
celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X
CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB
tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P
4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F
kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L
3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx
/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa
DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP
e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu
WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ
DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub
DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
-----END CERTIFICATE-----
SecureTrust CA
==============
-----BEGIN CERTIFICATE-----
@ -3609,3 +3416,65 @@ AgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J
fl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ
SwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4=
-----END CERTIFICATE-----
D-TRUST BR Root CA 2 2023
=========================
-----BEGIN CERTIFICATE-----
MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG
EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0Eg
MiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUwOTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTAT
BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCT
cfKri3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNEgXtRr90z
sWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8k12b9py0i4a6Ibn08OhZ
WiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCTRphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6
++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LUL
QyReS2tNZ9/WtT5PeB+UcSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIv
x9gvdhFP/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bSuREV
MweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+0bpwHJwh5Q8xaRfX
/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4NDfTisl01gLmB1IRpkQLLddCNxbU9
CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUZ5Dw1t61GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC
MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y
XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tIFoE9c+CeJyrr
d6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67nriv6uvw8l5VAk1/DLQOj7aRv
U9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTRVFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4
nj8+AybmTNudX0KEPUUDAxxZiMrcLmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdij
YQ6qgYF/6FKC0ULn4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff
/vtDhQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsGkoHU6XCP
pz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46ls/pdu4D58JDUjxqgejB
WoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aSEcr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/
5usWDiJFAbzdNpQ0qTUmiteXue4Icr80knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jt
n/mtd+ArY0+ew+43u3gJhJ65bvspmZDogNOfJA==
-----END CERTIFICATE-----
D-TRUST EV Root CA 2 2023
=========================
-----BEGIN CERTIFICATE-----
MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG
EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0Eg
MiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUwOTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTAT
BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1
sJkKF8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE7CUXFId/
MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFeEMbsh2aJgWi6zCudR3Mf
vc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6lHPTGGkKSv/BAQP/eX+1SH977ugpbzZM
lWGG2Pmic4ruri+W7mjNPU0oQvlFKzIbRlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3
YG14C8qKXO0elg6DpkiVjTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq910
7PncjLgcjmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZxTnXo
nMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ARZZaBhDM7DS3LAa
QzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nkhbDhezGdpn9yo7nELC7MmVcOIQxF
AZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knFNXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUqvyREBuHkV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC
MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y
XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14QvBukEdHjqOS
Mo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4pZt+UPJ26oUFKidBK7GB0aL2
QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xD
UmPBEcrCRbH0O1P1aa4846XerOhUt7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V
4U/M5d40VxDJI3IXcI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuo
dNv8ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT2vFp4LJi
TZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs7dpn1mKmS00PaaLJvOwi
S5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNPgofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/
HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAstNl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L
+KIkBI3Y4WNeApI02phhXBxvWHZks/wCuPWdCg==
-----END CERTIFICATE-----

View file

@ -61,17 +61,17 @@
},
{
"name": "composer/ca-bundle",
"version": "1.5.5",
"version_normalized": "1.5.5.0",
"version": "1.5.7",
"version_normalized": "1.5.7.0",
"source": {
"type": "git",
"url": "https://github.com/composer/ca-bundle.git",
"reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6"
"reference": "d665d22c417056996c59019579f1967dfe5c1e82"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/08c50d5ec4c6ced7d0271d2862dec8c1033283e6",
"reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6",
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/d665d22c417056996c59019579f1967dfe5c1e82",
"reference": "d665d22c417056996c59019579f1967dfe5c1e82",
"shasum": ""
},
"require": {
@ -85,7 +85,7 @@
"psr/log": "^1.0 || ^2.0 || ^3.0",
"symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"time": "2025-01-08T16:17:16+00:00",
"time": "2025-05-26T15:08:54+00:00",
"type": "library",
"extra": {
"branch-alias": {
@ -120,7 +120,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/ca-bundle/issues",
"source": "https://github.com/composer/ca-bundle/tree/1.5.5"
"source": "https://github.com/composer/ca-bundle/tree/1.5.7"
},
"funding": [
{
@ -346,17 +346,17 @@
},
{
"name": "enshrined/svg-sanitize",
"version": "0.21.0",
"version_normalized": "0.21.0.0",
"version": "0.22.0",
"version_normalized": "0.22.0.0",
"source": {
"type": "git",
"url": "https://github.com/darylldoyle/svg-sanitizer.git",
"reference": "5e477468fac5c5ce933dce53af3e8e4e58dcccc9"
"reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/5e477468fac5c5ce933dce53af3e8e4e58dcccc9",
"reference": "5e477468fac5c5ce933dce53af3e8e4e58dcccc9",
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/0afa95ea74be155a7bcd6c6fb60c276c39984500",
"reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500",
"shasum": ""
},
"require": {
@ -367,7 +367,7 @@
"require-dev": {
"phpunit/phpunit": "^6.5 || ^8.5"
},
"time": "2025-01-13T09:32:25+00:00",
"time": "2025-08-12T10:13:48+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -388,7 +388,7 @@
"description": "An SVG sanitizer for PHP",
"support": {
"issues": "https://github.com/darylldoyle/svg-sanitizer/issues",
"source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.21.0"
"source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.22.0"
},
"install-path": "../enshrined/svg-sanitize"
},
@ -585,17 +585,17 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "7.9.2",
"version_normalized": "7.9.2.0",
"version": "7.9.3",
"version_normalized": "7.9.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "d281ed313b989f213357e3be1a179f02196ac99b"
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b",
"reference": "d281ed313b989f213357e3be1a179f02196ac99b",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"shasum": ""
},
"require": {
@ -622,7 +622,7 @@
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"time": "2024-07-24T11:22:20+00:00",
"time": "2025-03-27T13:37:11+00:00",
"type": "library",
"extra": {
"bamarni-bin": {
@ -694,7 +694,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.9.2"
"source": "https://github.com/guzzle/guzzle/tree/7.9.3"
},
"funding": [
{
@ -714,17 +714,17 @@
},
{
"name": "guzzlehttp/promises",
"version": "2.0.4",
"version_normalized": "2.0.4.0",
"version": "2.2.0",
"version_normalized": "2.2.0.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455"
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
"url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
"shasum": ""
},
"require": {
@ -734,7 +734,7 @@
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
},
"time": "2024-10-17T10:06:22+00:00",
"time": "2025-03-27T13:27:01+00:00",
"type": "library",
"extra": {
"bamarni-bin": {
@ -780,7 +780,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.0.4"
"source": "https://github.com/guzzle/promises/tree/2.2.0"
},
"funding": [
{
@ -800,17 +800,17 @@
},
{
"name": "guzzlehttp/psr7",
"version": "2.7.0",
"version_normalized": "2.7.0.0",
"version": "2.7.1",
"version_normalized": "2.7.1.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"shasum": ""
},
"require": {
@ -831,7 +831,7 @@
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"time": "2024-07-18T11:15:46+00:00",
"time": "2025-03-27T12:30:47+00:00",
"type": "library",
"extra": {
"bamarni-bin": {
@ -899,7 +899,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.7.0"
"source": "https://github.com/guzzle/psr7/tree/2.7.1"
},
"funding": [
{
@ -1118,17 +1118,17 @@
},
{
"name": "matthiasmullie/minify",
"version": "1.3.73",
"version_normalized": "1.3.73.0",
"version": "1.3.75",
"version_normalized": "1.3.75.0",
"source": {
"type": "git",
"url": "https://github.com/matthiasmullie/minify.git",
"reference": "cb7a9297b4ab070909cefade30ee95054d4ae87a"
"reference": "76ba4a5f555fd7bf4aa408af608e991569076671"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/cb7a9297b4ab070909cefade30ee95054d4ae87a",
"reference": "cb7a9297b4ab070909cefade30ee95054d4ae87a",
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/76ba4a5f555fd7bf4aa408af608e991569076671",
"reference": "76ba4a5f555fd7bf4aa408af608e991569076671",
"shasum": ""
},
"require": {
@ -1139,13 +1139,12 @@
"require-dev": {
"friendsofphp/php-cs-fixer": ">=2.0",
"matthiasmullie/scrapbook": ">=1.3",
"phpunit/phpunit": ">=4.8",
"squizlabs/php_codesniffer": ">=3.0"
"phpunit/phpunit": ">=4.8"
},
"suggest": {
"psr/cache-implementation": "Cache implementation to use with Minify::cache"
},
"time": "2024-03-15T10:27:10+00:00",
"time": "2025-06-25T09:56:19+00:00",
"bin": [
"bin/minifycss",
"bin/minifyjs"
@ -1180,7 +1179,7 @@
],
"support": {
"issues": "https://github.com/matthiasmullie/minify/issues",
"source": "https://github.com/matthiasmullie/minify/tree/1.3.73"
"source": "https://github.com/matthiasmullie/minify/tree/1.3.75"
},
"funding": [
{
@ -1916,17 +1915,17 @@
},
{
"name": "symfony/polyfill-iconv",
"version": "v1.31.0",
"version_normalized": "1.31.0.0",
"version": "v1.32.0",
"version_normalized": "1.32.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git",
"reference": "48becf00c920479ca2e910c22a5a39e5d47ca956"
"reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956",
"reference": "48becf00c920479ca2e910c22a5a39e5d47ca956",
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/5f3b930437ae03ae5dff61269024d8ea1b3774aa",
"reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa",
"shasum": ""
},
"require": {
@ -1938,7 +1937,7 @@
"suggest": {
"ext-iconv": "For best performance"
},
"time": "2024-09-09T11:45:10+00:00",
"time": "2024-09-17T14:58:18+00:00",
"type": "library",
"extra": {
"thanks": {
@ -1979,7 +1978,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-iconv/tree/v1.32.0"
},
"funding": [
{
@ -1999,17 +1998,17 @@
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.31.0",
"version_normalized": "1.31.0.0",
"version": "v1.32.0",
"version_normalized": "1.32.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773"
"reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773",
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3",
"reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3",
"shasum": ""
},
"require": {
@ -2019,7 +2018,7 @@
"suggest": {
"ext-intl": "For best performance"
},
"time": "2024-09-09T11:45:10+00:00",
"time": "2024-09-10T14:38:51+00:00",
"type": "library",
"extra": {
"thanks": {
@ -2065,7 +2064,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0"
},
"funding": [
{
@ -2085,8 +2084,8 @@
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.31.0",
"version_normalized": "1.31.0.0",
"version": "v1.32.0",
"version_normalized": "1.32.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@ -2149,7 +2148,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
},
"funding": [
{
@ -2169,20 +2168,21 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.31.0",
"version_normalized": "1.31.0.0",
"version": "v1.32.0",
"version_normalized": "1.32.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": ">=7.2"
},
"provide": {
@ -2191,7 +2191,7 @@
"suggest": {
"ext-mbstring": "For best performance"
},
"time": "2024-09-09T11:45:10+00:00",
"time": "2024-12-23T08:48:59+00:00",
"type": "library",
"extra": {
"thanks": {
@ -2232,7 +2232,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
},
"funding": [
{

View file

@ -3,7 +3,7 @@
'name' => 'rhymix/rhymix',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '074873d844582d33f53959d8c3595d5019b9ae5c',
'reference' => 'fad0bc91533b8a39af5512e073dfcdcad4d74133',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -20,9 +20,9 @@
'dev_requirement' => false,
),
'composer/ca-bundle' => array(
'pretty_version' => '1.5.5',
'version' => '1.5.5.0',
'reference' => '08c50d5ec4c6ced7d0271d2862dec8c1033283e6',
'pretty_version' => '1.5.7',
'version' => '1.5.7.0',
'reference' => 'd665d22c417056996c59019579f1967dfe5c1e82',
'type' => 'library',
'install_path' => __DIR__ . '/./ca-bundle',
'aliases' => array(),
@ -56,9 +56,9 @@
'dev_requirement' => false,
),
'enshrined/svg-sanitize' => array(
'pretty_version' => '0.21.0',
'version' => '0.21.0.0',
'reference' => '5e477468fac5c5ce933dce53af3e8e4e58dcccc9',
'pretty_version' => '0.22.0',
'version' => '0.22.0.0',
'reference' => '0afa95ea74be155a7bcd6c6fb60c276c39984500',
'type' => 'library',
'install_path' => __DIR__ . '/../enshrined/svg-sanitize',
'aliases' => array(),
@ -92,27 +92,27 @@
'dev_requirement' => false,
),
'guzzlehttp/guzzle' => array(
'pretty_version' => '7.9.2',
'version' => '7.9.2.0',
'reference' => 'd281ed313b989f213357e3be1a179f02196ac99b',
'pretty_version' => '7.9.3',
'version' => '7.9.3.0',
'reference' => '7b2f29fe81dc4da0ca0ea7d42107a0845946ea77',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/promises' => array(
'pretty_version' => '2.0.4',
'version' => '2.0.4.0',
'reference' => 'f9c436286ab2892c7db7be8c8da4ef61ccf7b455',
'pretty_version' => '2.2.0',
'version' => '2.2.0.0',
'reference' => '7c69f28996b0a6920945dd20b3857e499d9ca96c',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '2.7.0',
'version' => '2.7.0.0',
'reference' => 'a70f5c95fb43bc83f07c9c948baa0dc1829bf201',
'pretty_version' => '2.7.1',
'version' => '2.7.1.0',
'reference' => 'c2270caaabe631b3b44c85f99e5a04bbb8060d16',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
@ -154,9 +154,9 @@
'dev_requirement' => false,
),
'matthiasmullie/minify' => array(
'pretty_version' => '1.3.73',
'version' => '1.3.73.0',
'reference' => 'cb7a9297b4ab070909cefade30ee95054d4ae87a',
'pretty_version' => '1.3.75',
'version' => '1.3.75.0',
'reference' => '76ba4a5f555fd7bf4aa408af608e991569076671',
'type' => 'library',
'install_path' => __DIR__ . '/../matthiasmullie/minify',
'aliases' => array(),
@ -255,7 +255,7 @@
'rhymix/rhymix' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '074873d844582d33f53959d8c3595d5019b9ae5c',
'reference' => 'fad0bc91533b8a39af5512e073dfcdcad4d74133',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -298,26 +298,26 @@
'dev_requirement' => false,
),
'symfony/polyfill-iconv' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
'reference' => '48becf00c920479ca2e910c22a5a39e5d47ca956',
'pretty_version' => 'v1.32.0',
'version' => '1.32.0.0',
'reference' => '5f3b930437ae03ae5dff61269024d8ea1b3774aa',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-iconv',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-idn' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
'reference' => 'c36586dcf89a12315939e00ec9b4474adcb1d773',
'pretty_version' => 'v1.32.0',
'version' => '1.32.0.0',
'reference' => '9614ac4d8061dc257ecc64cba1b140873dce8ad3',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
'pretty_version' => 'v1.32.0',
'version' => '1.32.0.0',
'reference' => '3833d7255cc303546435cb650316bff708a1c75c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
@ -325,9 +325,9 @@
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341',
'pretty_version' => 'v1.32.0',
'version' => '1.32.0.0',
'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),

View file

@ -421,7 +421,7 @@ class Sanitizer
* Such as xlink:href when the xlink namespace isn't imported.
* We have to do this as the link is still ran in this case.
*/
if (false !== strpos($attrName, 'href')) {
if (false !== stripos($attrName, 'href')) {
$href = $element->getAttribute($attrName);
if (false === $this->isHrefSafeValue($href)) {
$element->removeAttribute($attrName);
@ -453,15 +453,18 @@ class Sanitizer
*/
protected function cleanXlinkHrefs(\DOMElement $element)
{
$xlinks = $element->getAttributeNS('http://www.w3.org/1999/xlink', 'href');
if (false === $this->isHrefSafeValue($xlinks)) {
$element->removeAttributeNS( 'http://www.w3.org/1999/xlink', 'href' );
foreach ($element->attributes as $attribute) {
// remove attributes with unexpected namespace prefix, e.g. `XLinK:href` (instead of `xlink:href`)
if ($attribute->prefix === '' && strtolower($attribute->nodeName) === 'xlink:href') {
$element->removeAttribute($attribute->nodeName);
$this->xmlIssues[] = array(
'message' => 'Suspicious attribute \'href\'',
'message' => sprintf('Unexpected attribute \'%s\'', $attribute->nodeName),
'line' => $element->getLineNo(),
);
}
}
$this->cleanHrefAttributes($element, 'xlink');
}
/**
* Clean the hrefs of script and data embeds
@ -470,13 +473,33 @@ class Sanitizer
*/
protected function cleanHrefs(\DOMElement $element)
{
$href = $element->getAttribute('href');
if (false === $this->isHrefSafeValue($href)) {
$element->removeAttribute('href');
$this->cleanHrefAttributes($element);
}
protected function cleanHrefAttributes(\DOMElement $element, string $prefix = ''): void
{
$relevantAttributes = array_filter(
iterator_to_array($element->attributes),
static function (\DOMAttr $attr) use ($prefix) {
return strtolower($attr->name) === 'href' && strtolower($attr->prefix) === $prefix;
}
);
foreach ($relevantAttributes as $attribute) {
if (!$this->isHrefSafeValue($attribute->value)) {
$element->removeAttribute($attribute->nodeName);
$this->xmlIssues[] = array(
'message' => 'Suspicious attribute \'href\'',
'message' => sprintf('Suspicious attribute \'%s\'', $attribute->nodeName),
'line' => $element->getLineNo(),
);
continue;
}
// in case the attribute name is `HrEf`/`xlink:HrEf`, adjust it to `href`/`xlink:href`
if (!in_array($attribute->nodeName, $this->allowedAttrs, true)
&& in_array(strtolower($attribute->nodeName), $this->allowedAttrs, true)
) {
$element->removeAttribute($attribute->nodeName);
$element->setAttribute(strtolower($attribute->nodeName), $attribute->value);
}
}
}

View file

@ -3,6 +3,14 @@
Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version.
## 7.9.3 - 2025-03-27
### Changed
- Remove explicit content-length header for GET requests
- Improve compatibility with bad servers for boolean cookie values
## 7.9.2 - 2024-07-24
### Fixed

View file

@ -62,6 +62,10 @@ class SetCookie
if (is_numeric($value)) {
$data[$search] = (int) $value;
}
} elseif ($search === 'Secure' || $search === 'Discard' || $search === 'HttpOnly') {
if ($value) {
$data[$search] = true;
}
} else {
$data[$search] = $value;
}

View file

@ -17,10 +17,10 @@ class Proxy
* Sends synchronous requests to a specific handler while sending all other
* requests to another handler.
*
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for normal responses
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $sync Handler used for synchronous responses.
* @param callable(RequestInterface, array): PromiseInterface $default Handler used for normal responses
* @param callable(RequestInterface, array): PromiseInterface $sync Handler used for synchronous responses.
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
* @return callable(RequestInterface, array): PromiseInterface Returns the composed handler.
*/
public static function wrapSync(callable $default, callable $sync): callable
{
@ -37,10 +37,10 @@ class Proxy
* performance benefits of curl while still supporting true streaming
* through the StreamHandler.
*
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for non-streaming responses
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $streaming Handler used for streaming responses
* @param callable(RequestInterface, array): PromiseInterface $default Handler used for non-streaming responses
* @param callable(RequestInterface, array): PromiseInterface $streaming Handler used for streaming responses
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
* @return callable(RequestInterface, array): PromiseInterface Returns the composed handler.
*/
public static function wrapStreaming(callable $default, callable $streaming): callable
{

View file

@ -53,8 +53,14 @@ class StreamHandler
$request = $request->withoutHeader('Expect');
// Append a content-length header if body size is zero to match
// cURL's behavior.
if (0 === $request->getBody()->getSize()) {
// the behavior of `CurlHandler`
if (
(
0 === \strcasecmp('PUT', $request->getMethod())
|| 0 === \strcasecmp('POST', $request->getMethod())
)
&& 0 === $request->getBody()->getSize()
) {
$request = $request->withHeader('Content-Length', '0');
}

View file

@ -86,7 +86,7 @@ class Pool implements PromisorInterface
* @param ClientInterface $client Client used to send the requests
* @param array|\Iterator $requests Requests to send concurrently.
* @param array $options Passes through the options available in
* {@see \GuzzleHttp\Pool::__construct}
* {@see Pool::__construct}
*
* @return array Returns an array containing the response or an exception
* in the same order that the requests were sent.

View file

@ -79,7 +79,7 @@ final class Utils
*
* The returned handler is not wrapped by any default middlewares.
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.
* @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system.
*
* @throws \RuntimeException if no viable Handler is available.
*/

View file

@ -50,7 +50,7 @@ function debug_resource($value = null)
*
* The returned handler is not wrapped by any default middlewares.
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.
* @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system.
*
* @throws \RuntimeException if no viable Handler is available.
*

View file

@ -1,6 +1,20 @@
# CHANGELOG
## 2.2.0 - 2025-03-27
### Fixed
- Revert "Allow an empty EachPromise to be resolved by running the queue"
## 2.1.0 - 2025-03-27
### Added
- Allow an empty EachPromise to be resolved by running the queue
## 2.0.4 - 2024-10-17
### Fixed

View file

@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 2.7.1 - 2025-03-27
### Fixed
- Fixed uppercase IPv6 addresses in URI
### Changed
- Improve uploaded file error message
## 2.7.0 - 2024-07-18
### Added

View file

@ -11,15 +11,15 @@ use RuntimeException;
class UploadedFile implements UploadedFileInterface
{
private const ERRORS = [
UPLOAD_ERR_OK,
UPLOAD_ERR_INI_SIZE,
UPLOAD_ERR_FORM_SIZE,
UPLOAD_ERR_PARTIAL,
UPLOAD_ERR_NO_FILE,
UPLOAD_ERR_NO_TMP_DIR,
UPLOAD_ERR_CANT_WRITE,
UPLOAD_ERR_EXTENSION,
private const ERROR_MAP = [
UPLOAD_ERR_OK => 'UPLOAD_ERR_OK',
UPLOAD_ERR_INI_SIZE => 'UPLOAD_ERR_INI_SIZE',
UPLOAD_ERR_FORM_SIZE => 'UPLOAD_ERR_FORM_SIZE',
UPLOAD_ERR_PARTIAL => 'UPLOAD_ERR_PARTIAL',
UPLOAD_ERR_NO_FILE => 'UPLOAD_ERR_NO_FILE',
UPLOAD_ERR_NO_TMP_DIR => 'UPLOAD_ERR_NO_TMP_DIR',
UPLOAD_ERR_CANT_WRITE => 'UPLOAD_ERR_CANT_WRITE',
UPLOAD_ERR_EXTENSION => 'UPLOAD_ERR_EXTENSION',
];
/**
@ -104,7 +104,7 @@ class UploadedFile implements UploadedFileInterface
*/
private function setError(int $error): void
{
if (false === in_array($error, UploadedFile::ERRORS, true)) {
if (!isset(UploadedFile::ERROR_MAP[$error])) {
throw new InvalidArgumentException(
'Invalid error status for UploadedFile'
);
@ -137,7 +137,7 @@ class UploadedFile implements UploadedFileInterface
private function validateActive(): void
{
if (false === $this->isOk()) {
throw new RuntimeException('Cannot retrieve stream due to upload error');
throw new RuntimeException(\sprintf('Cannot retrieve stream due to upload error (%s)', self::ERROR_MAP[$this->error]));
}
if ($this->isMoved()) {

View file

@ -107,7 +107,7 @@ class Uri implements UriInterface, \JsonSerializable
{
// If IPv6
$prefix = '';
if (preg_match('%^(.*://\[[0-9:a-f]+\])(.*?)$%', $url, $matches)) {
if (preg_match('%^(.*://\[[0-9:a-fA-F]+\])(.*?)$%', $url, $matches)) {
/** @var array{0:string, 1:string, 2:string} $matches */
$prefix = $matches[1];
$url = $matches[2];

View file

@ -21,8 +21,7 @@
"require-dev": {
"friendsofphp/php-cs-fixer": ">=2.0",
"matthiasmullie/scrapbook": ">=1.3",
"phpunit/phpunit": ">=4.8",
"squizlabs/php_codesniffer": ">=3.0"
"phpunit/phpunit": ">=4.8"
},
"suggest": {
"psr/cache-implementation": "Cache implementation to use with Minify::cache"

View file

@ -1,10 +0,0 @@
<?xml version="1.0"?>
<ruleset>
<rule ref="PSR12" />
<file>./src</file>
<file>./tests</file>
<arg name="extensions" value="php" />
<arg name="encoding" value="UTF-8" />
</ruleset>

View file

@ -13,6 +13,7 @@
namespace MatthiasMullie\Minify;
use MatthiasMullie\Minify\Exceptions\FileImportException;
use MatthiasMullie\Minify\Exceptions\PatternMatchException;
use MatthiasMullie\PathConverter\Converter;
use MatthiasMullie\PathConverter\ConverterInterface;
@ -296,6 +297,8 @@ class CSS extends Minify
* @param string[] $parents Parent paths, for circular reference checks
*
* @return string The minified data
*
* @throws PatternMatchException
*/
public function execute($path = null, $parents = array())
{
@ -590,6 +593,7 @@ class CSS extends Minify
// convert `rgb` to `hex`
$dec = '([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])';
return preg_replace_callback(
"/rgb\($dec $dec $dec\)/i",
function ($match) {
@ -621,10 +625,10 @@ class CSS extends Minify
$tag = '(rgb|hsl|hwb|(?:(?:ok)?(?:lch|lab)))';
// remove alpha channel if it's pointless ..
$content = preg_replace('/' . $tag . '\(\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+\/\s+1(?:(?:\.\d?)*|00%)?\s*\)/i', '$1($2 $3 $4)', $content);
$content = preg_replace('/' . $tag . '\(\s*([^\s)]+)\s+([^\s)]+)\s+([^\s)]+)\s+\/\s+1(?:(?:\.\d?)*|00%)?\s*\)/i', '$1($2 $3 $4)', $content);
// replace `transparent` with shortcut ..
$content = preg_replace('/' . $tag . '\(\s*[^\s]+\s+[^\s]+\s+[^\s]+\s+\/\s+0(?:[\.0%]*)?\s*\)/i', '#fff0', $content);
$content = preg_replace('/' . $tag . '\(\s*[^\s)]+\s+[^\s)]+\s+[^\s)]+\s+\/\s+0(?:[\.0%]*)?\s*\)/i', '#fff0', $content);
return $content;
}
@ -732,29 +736,31 @@ class CSS extends Minify
* @param string $content The CSS content to strip the whitespace for
*
* @return string
*
* @throws PatternMatchException
*/
protected function stripWhitespace($content)
{
// remove leading & trailing whitespace
$content = preg_replace('/^\s*/m', '', $content);
$content = preg_replace('/\s*$/m', '', $content);
$content = $this->pregReplace('/^\s*/m', '', $content);
$content = $this->pregReplace('/\s*$/m', '', $content);
// replace newlines with a single space
$content = preg_replace('/\s+/', ' ', $content);
$content = $this->pregReplace('/\s+/', ' ', $content);
// remove whitespace around meta characters
// inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex
$content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
$content = preg_replace('/([\[(:>\+])\s+/', '$1', $content);
$content = preg_replace('/\s+([\]\)>\+])/', '$1', $content);
$content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
$content = $this->pregReplace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
$content = $this->pregReplace('/([\[(:>\+])\s+/', '$1', $content);
$content = $this->pregReplace('/\s+([\]\)>\+])/', '$1', $content);
$content = $this->pregReplace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
// whitespace around + and - can only be stripped inside some pseudo-
// classes, like `:nth-child(3+2n)`
// not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or
// selectors like `div.weird- p`
$pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type');
$content = preg_replace('/:(' . implode('|', $pseudos) . ')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
$content = $this->pregReplace('/:(' . implode('|', $pseudos) . ')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
// remove semicolon/whitespace followed by closing bracket
$content = str_replace(';}', '}', $content);
@ -762,6 +768,27 @@ class CSS extends Minify
return trim($content);
}
/**
* Perform a preg_replace and check for errors.
*
* @param string $pattern Pattern
* @param string $replacement Replacement
* @param string $subject String to process
*
* @return string
*
* @throws PatternMatchException
*/
protected function pregReplace($pattern, $replacement, $subject)
{
$result = preg_replace($pattern, $replacement, $subject);
if ($result === null) {
throw PatternMatchException::fromLastError("Failed to replace with pattern '$pattern'");
}
return $result;
}
/**
* Replace all occurrences of functions that may contain math, where
* whitespace around operators needs to be preserved (e.g. calc, clamp).

View file

@ -17,6 +17,4 @@ namespace MatthiasMullie\Minify;
*
* @author Matthias Mullie <minify@mullie.eu>
*/
abstract class Exception extends \Exception
{
}
abstract class Exception extends \Exception {}

View file

@ -19,6 +19,4 @@ use MatthiasMullie\Minify\Exception;
*
* @author Matthias Mullie <minify@mullie.eu>
*/
abstract class BasicException extends Exception
{
}
abstract class BasicException extends Exception {}

View file

@ -17,6 +17,4 @@ namespace MatthiasMullie\Minify\Exceptions;
*
* @author Matthias Mullie <minify@mullie.eu>
*/
class FileImportException extends BasicException
{
}
class FileImportException extends BasicException {}

View file

@ -17,6 +17,4 @@ namespace MatthiasMullie\Minify\Exceptions;
*
* @author Matthias Mullie <minify@mullie.eu>
*/
class IOException extends BasicException
{
}
class IOException extends BasicException {}

View file

@ -0,0 +1,36 @@
<?php
/**
* Pattern match exception.
*
* Please report bugs on https://github.com/matthiasmullie/minify/issues
*
* @author Ere Maijala <ere.maijala@helsinki.fi>
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
* @license MIT License
*/
namespace MatthiasMullie\Minify\Exceptions;
/**
* Pattern Match Exception Class.
*
* @author Ere Maijala <ere.maijala@helsinki.fi>
*/
class PatternMatchException extends BasicException
{
/**
* Create an exception from preg_last_error.
*
* @param string $msg Error message
*/
public static function fromLastError($msg)
{
$msg .= ': Error ' . preg_last_error();
if (PHP_MAJOR_VERSION >= 8) {
$msg .= ' - ' . preg_last_error_msg();
}
return new PatternMatchException($msg);
}
}

View file

@ -13,6 +13,7 @@
namespace MatthiasMullie\Minify;
use MatthiasMullie\Minify\Exceptions\IOException;
use MatthiasMullie\Minify\Exceptions\PatternMatchException;
use Psr\Cache\CacheItemInterface;
/**
@ -265,23 +266,9 @@ abstract class Minify
*/
protected function stripMultilineComments()
{
// First extract comments we want to keep, so they can be restored later
// PHP only supports $this inside anonymous functions since 5.4
$minifier = $this;
$callback = function ($match) use ($minifier) {
$count = count($minifier->extracted);
$placeholder = '/*' . $count . '*/';
$minifier->extracted[$placeholder] = $match[0];
return $placeholder;
};
$this->registerPattern('/
# optional newline
\n?
# start comment
\/\*
// Pattern for matching comments that we want to preserve
$keepPattern = '/^
# comment content
(?:
# either starts with an !
@ -293,14 +280,24 @@ abstract class Minify
# there is either a @license or @preserve tag
@(?:license|preserve)
)
/ixs';
$callback = function ($match) use ($minifier, $keepPattern) {
if (preg_match($keepPattern, $match[1])) {
// Preserve the comment
$count = count($minifier->extracted);
$placeholder = '/*' . $count . '*/';
$minifier->extracted[$placeholder] = $match[0];
} else {
// Discard the comment but keep any single line feed
$placeholder = strncmp($match[0], "\n", 1) === 0 || substr($match[0], -1) === "\n"
? "\n"
: '';
}
# then match to the end of the comment
.*?\*\/\n?
return $placeholder;
};
/ixs', $callback);
// Then strip all other comments
$this->registerPattern('/\/\*.*?\*\//s', '');
$this->registerPattern('/\n?\/\*(.*?)\*\/\n?/s', $callback);
}
/**
@ -314,6 +311,8 @@ abstract class Minify
* @param string $content The content to replace patterns in
*
* @return string The (manipulated) content
*
* @throws PatternMatchException
*/
protected function replace($content)
{
@ -341,7 +340,8 @@ abstract class Minify
}
$match = null;
if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE, $processedOffset)) {
$matchResult = preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE, $processedOffset);
if ($matchResult) {
$matches[$i] = $match;
// we'll store the match position as well; that way, we
@ -349,6 +349,11 @@ abstract class Minify
// the first (we'll still know where those others are)
$positions[$i] = $match[0][1];
} else {
if ($matchResult === false) {
throw PatternMatchException::fromLastError(
"Failed to match pattern '$pattern' at $processedOffset"
);
}
// if the pattern couldn't be matched, there's no point in
// executing it again in later runs on this same content;
// ignore this one until we reach end of content
@ -445,6 +450,11 @@ abstract class Minify
};
/*
* Quantifier {0,65535} is used instead of *? to avoid exceeding
* backtrack limit with large strings. 65535 is the maximum allowed
* (see https://www.php.net/manual/en/regexp.reference.repetition.php)
* and should be well sufficient for string representations here.
*
* The \\ messiness explained:
* * Don't count ' or " as end-of-string if it's escaped (has backslash
* in front of it)
@ -456,7 +466,8 @@ abstract class Minify
* considered as escape-char (times 2) and to get it in the regex,
* escaped (times 2)
*/
$this->registerPattern('/([' . $chars . '])(.*?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
$this->registerPattern('/([' . $chars . '])(.{0,65535}?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
}
/**

View file

@ -429,32 +429,6 @@ final class Iconv
}
public static function iconv_strlen($s, $encoding = null)
{
static $hasXml = null;
if (null === $hasXml) {
$hasXml = \extension_loaded('xml');
}
if ($hasXml) {
return self::strlen1($s, $encoding);
}
return self::strlen2($s, $encoding);
}
public static function strlen1($s, $encoding = null)
{
if (null === $encoding) {
$encoding = self::$internalEncoding;
}
if (0 !== stripos($encoding, 'utf-8') && false === $s = self::iconv($encoding, 'utf-8', $s)) {
return false;
}
return \strlen(utf8_decode($s));
}
public static function strlen2($s, $encoding = null)
{
if (null === $encoding) {
$encoding = self::$internalEncoding;

View file

@ -66,11 +66,7 @@ if (extension_loaded('mbstring')) {
}
} else {
if (!function_exists('iconv_strlen')) {
if (extension_loaded('xml')) {
function iconv_strlen($string, $encoding = null) { return p\Iconv::strlen1($string, $encoding); }
} else {
function iconv_strlen($string, $encoding = null) { return p\Iconv::strlen2($string, $encoding); }
}
function iconv_strlen($string, $encoding = null) { return p\Iconv::iconv_strlen($string, $encoding); }
}
if (!function_exists('iconv_strpos')) {

View file

@ -58,11 +58,7 @@ if (extension_loaded('mbstring')) {
}
} else {
if (!function_exists('iconv_strlen')) {
if (extension_loaded('xml')) {
function iconv_strlen(?string $string, ?string $encoding = null): int|false { return p\Iconv::strlen1((string) $string, $encoding); }
} else {
function iconv_strlen(?string $string, ?string $encoding = null): int|false { return p\Iconv::strlen2((string) $string, $encoding); }
}
function iconv_strlen(?string $string, ?string $encoding = null): int|false { return p\Iconv::iconv_strlen((string) $string, $encoding); }
}
if (!function_exists('iconv_strpos')) {

View file

@ -145,6 +145,10 @@ final class Idn
*/
public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
{
if (\PHP_VERSION_ID > 80400 && '' === $domainName) {
throw new \ValueError('idn_to_ascii(): Argument #1 ($domain) cannot be empty');
}
if (self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
}
@ -198,6 +202,10 @@ final class Idn
*/
public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
{
if (\PHP_VERSION_ID > 80400 && '' === $domainName) {
throw new \ValueError('idn_to_utf8(): Argument #1 ($domain) cannot be empty');
}
if (self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
}

View file

@ -983,7 +983,7 @@ final class Mbstring
public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string
{
return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__);
return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
}
private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string

View file

@ -133,11 +133,11 @@ if (!function_exists('mb_str_pad')) {
}
if (!function_exists('mb_ucfirst')) {
function mb_ucfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
}
if (!function_exists('mb_lcfirst')) {
function mb_lcfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
}
if (!function_exists('mb_trim')) {

View file

@ -16,7 +16,8 @@
}
],
"require": {
"php": ">=7.2"
"php": ">=7.2",
"ext-iconv": "*"
},
"provide": {
"ext-mbstring": "*"

View file

@ -67,26 +67,12 @@ class CommentAdminView extends Comment
Context::set('secret_name_list', $secretNameList);
// Module List
$oModuleModel = getModel('module');
$module_list = array();
$mod_srls = array();
foreach($output->data as $val)
$module_list = [];
$mod_output = executeQueryArray('comment.getModuleList');
foreach ($mod_output->data as $item)
{
$mod_srls[] = $val->module_srl;
}
$mod_srls = array_unique($mod_srls);
$mod_srls_count = count($mod_srls);
if($mod_srls_count)
{
$columnList = array('module_srl', 'mid', 'browser_title');
$module_output = $oModuleModel->getModulesInfo($mod_srls, $columnList);
if($module_output && is_array($module_output))
{
foreach($module_output as $module)
{
$module_list[$module->module_srl] = $module;
}
}
$item->browser_title = Context::replaceUserLang($item->browser_title);
$module_list[$item->module_srl] = $item;
}
Context::set('module_list', $module_list);
@ -115,8 +101,9 @@ class CommentAdminView extends Comment
}
Context::set('member_nick_name', $member_nick_name);
$security = new Security();
$security->encodeHTML('search_target', 'search_keyword');
// Other search options
Context::set('search_target', escape(Context::get('search_target'), false));
Context::set('search_keyword', escape(Context::get('search_keyword'), false));
// set the template
$this->setTemplatePath($this->module_path . 'tpl');

View file

@ -1606,9 +1606,16 @@ class CommentController extends Comment
}
// invalid vote if vote info exists in the session info.
if(!empty($_SESSION['voted_comment'][$comment_srl]))
if (!empty($_SESSION['voted_comment'][$comment_srl]))
{
return new BaseObject(-1, $failed_voted . '_already');
if ($_SESSION['voted_comment'][$comment_srl] > 0)
{
return new BaseObject(-1, 'failed_voted_already');
}
else
{
return new BaseObject(-1, 'failed_blamed_already');
}
}
// Get the original comment
@ -1650,10 +1657,17 @@ class CommentController extends Comment
$output = executeQuery('comment.getCommentVotedLogInfo', $args);
// Pass after registering a session if log information has vote-up logs
if($output->data->count)
if ($output->data->count)
{
$_SESSION['voted_comment'][$comment_srl] = false;
return new BaseObject(-1, $failed_voted);
$_SESSION['voted_comment'][$comment_srl] = intval($output->data->point);
if ($output->data->point > 0)
{
return new BaseObject(-1, 'failed_voted_already');
}
else
{
return new BaseObject(-1, 'failed_blamed_already');
}
}
// Call a trigger (before)

View file

@ -594,7 +594,7 @@ class CommentItem extends BaseObject
// Truncate string
$content = cut_str($content, $str_size, $tail);
$content = escape($content);
$content = escape($content, false);
if ($content === '')
{

View file

@ -4,6 +4,7 @@
</tables>
<columns>
<column name="count(*)" alias="count" />
<column name="sum(point)" alias="point" />
</columns>
<conditions>
<condition operation="equal" column="comment_srl" var="comment_srl" filter="number" notnull="notnull" />

View file

@ -0,0 +1,20 @@
<query id="getModuleList" action="select">
<tables>
<table name="modules" />
</tables>
<columns>
<column name="module_srl" />
<column name="mid" />
<column name="browser_title" />
</columns>
<conditions>
<query operation="in" column="module_srl">
<tables>
<table name="comments" />
</tables>
<columns distinct="distinct">
<column name="module_srl" />
</columns>
</query>
</conditions>
</query>

View file

@ -124,8 +124,13 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<form action="./" method="get" class="search center x_input-append" onsubmit="return checkSearch(this)">
<input type="hidden" name="module" value="{$module}" />
<input type="hidden" name="act" value="{$act}" />
<input type="hidden" name="module_srl" value="{$module_srl}" />
<input type="hidden" name="error_return_url" value="" />
<select name="module_srl" style="margin-right:4px">
<option value="">{lang('all')}</option>
<!--@foreach($module_list as $item)-->
<option value="{$item->module_srl}" <!--@if(isset($module_srl) && $module_srl == $item->module_srl)-->selected="selected"<!--@end-->>{$item->browser_title}</option>
<!--@endforeach-->
</select>
<select name="search_target" title="{$lang->search_target}" style="margin-right:4px">
<!--@foreach(lang('comment.search_target_list') as $key => $val)-->
<option value="{$key}" <!--@if($search_target==$key)-->selected="selected"<!--@end-->>{$val}</option>

View file

@ -82,26 +82,12 @@ class DocumentAdminView extends Document
Context::set('search_option', $search_option);
// Module List
$oModuleModel = getModel('module');
$module_list = array();
$mod_srls = array();
foreach($output->data as $oDocument)
$module_list = [];
$mod_output = executeQueryArray('document.getModuleList');
foreach ($mod_output->data as $item)
{
$mod_srls[] = $oDocument->get('module_srl');
}
$mod_srls = array_unique($mod_srls);
$mod_srls_count = count($mod_srls);
if($mod_srls_count)
{
$columnList = array('module_srl', 'mid', 'browser_title');
$module_output = $oModuleModel->getModulesInfo($mod_srls, $columnList);
if($module_output && is_array($module_output))
{
foreach($module_output as $module)
{
$module_list[$module->module_srl] = $module;
}
}
$item->browser_title = Context::replaceUserLang($item->browser_title);
$module_list[$item->module_srl] = $item;
}
Context::set('module_list', $module_list);
@ -130,8 +116,10 @@ class DocumentAdminView extends Document
}
Context::set('member_nick_name', $member_nick_name);
$security = new Security();
$security->encodeHTML('search_target', 'search_keyword');
// Other search options
Context::set('search_target', escape(Context::get('search_target'), false));
Context::set('search_keyword', escape(Context::get('search_keyword'), false));
Context::set('is_secret', Context::get('is_secret') === 'Y' ? 'Y' : 'N');
// Specify a template
$this->setTemplatePath($this->module_path.'tpl');

View file

@ -2032,9 +2032,16 @@ class DocumentController extends Document
}
// Return fail if session already has information about votes
if(!empty($_SESSION['voted_document'][$document_srl]))
if (!empty($_SESSION['voted_document'][$document_srl]))
{
return new BaseObject(-1, $failed_voted . '_already');
if ($_SESSION['voted_document'][$document_srl] > 0)
{
return new BaseObject(-1, 'failed_voted_already');
}
else
{
return new BaseObject(-1, 'failed_blamed_already');
}
}
// Get the original document
@ -2076,10 +2083,17 @@ class DocumentController extends Document
$output = executeQuery('document.getDocumentVotedLogInfo', $args);
// Pass after registering a session if log information has vote-up logs
if($output->data->count)
if ($output->data->count)
{
$_SESSION['voted_document'][$document_srl] = false;
return new BaseObject(-1, $failed_voted);
$_SESSION['voted_document'][$document_srl] = intval($output->data->point);
if ($output->data->point > 0)
{
return new BaseObject(-1, 'failed_voted_already');
}
else
{
return new BaseObject(-1, 'failed_blamed_already');
}
}
// Call a trigger (before)

View file

@ -0,0 +1,20 @@
<query id="getModuleList" action="select">
<tables>
<table name="modules" />
</tables>
<columns>
<column name="module_srl" />
<column name="mid" />
<column name="browser_title" />
</columns>
<conditions>
<query operation="in" column="module_srl">
<tables>
<table name="documents" />
</tables>
<columns distinct="distinct">
<column name="module_srl" />
</columns>
</query>
</conditions>
</query>

View file

@ -120,8 +120,13 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<form action="./" method="get" class="search center x_input-append x_clearfix">
<input type="hidden" name="module" value="{$module}" />
<input type="hidden" name="act" value="{$act}" />
<input type="hidden" name="module_srl" value="{$module_srl}" />
<input type="hidden" name="error_return_url" value="" />
<select name="module_srl" style="margin-right:4px">
<option value="">{lang('all')}</option>
<!--@foreach($module_list as $item)-->
<option value="{$item->module_srl}" <!--@if(isset($module_srl) && $module_srl == $item->module_srl)-->selected="selected"<!--@end-->>{$item->browser_title}</option>
<!--@endforeach-->
</select>
<select name="search_target" title="{$lang->search_target}" style="margin-right:4px">
<!--@foreach(lang('document.search_target_list') as $key => $val)-->
<option value="{$key}" <!--@if($search_target==$key)-->selected="selected"<!--@end-->>{$val}</option>

View file

@ -136,7 +136,7 @@ class EditorModel extends Editor
{
if(empty($_SESSION['_editor_sequence_']))
{
$_SESSION['_editor_sequence_'] = 1;
$_SESSION['_editor_sequence_'] = 4;
}
$option->editor_sequence = $_SESSION['_editor_sequence_']++;
}

View file

@ -25,6 +25,9 @@
<option value=""></option>
@foreach ($countries as $country)
@php
if (!$country->calling_code) {
continue;
}
$country_name = $lang_type === 'ko' ? $country->name_korean : $country->name_english;
if ($selected_iso_code) {
$is_selected = $selected_iso_code === $country->iso_3166_1_alpha3;

View file

@ -37,7 +37,7 @@ class FileAdminView extends File
$file_list = array();
$document_list = array();
$comment_list = array();
$module_list= array();
$module_list = array();
$doc_srls = array();
$com_srls = array();
@ -162,20 +162,6 @@ class FileAdminView extends File
}
}
}
// Module List
$mod_srls_count = count($mod_srls);
if($mod_srls_count)
{
$columnList = array('module_srl', 'mid', 'browser_title');
$module_output = $oModuleModel->getModulesInfo($mod_srls, $columnList);
if($module_output && is_array($module_output))
{
foreach($module_output as $module)
{
$module_list[$module->module_srl] = $module;
}
}
}
foreach($file_list as $srl => $file)
{
@ -186,6 +172,15 @@ class FileAdminView extends File
}
}
// Module list
$mod_output = executeQueryArray('comment.getModuleList');
foreach ($mod_output->data as $item)
{
$item->browser_title = Context::replaceUserLang($item->browser_title);
$module_list[$item->module_srl] = $item;
}
Context::set('module_list', $module_list);
Context::set('file_list', $file_list);
Context::set('document_list', $document_list);
Context::set('comment_list', $comment_list);

View file

@ -0,0 +1,20 @@
<query id="getModuleList" action="select">
<tables>
<table name="modules" />
</tables>
<columns>
<column name="module_srl" />
<column name="mid" />
<column name="browser_title" />
</columns>
<conditions>
<query operation="in" column="module_srl">
<tables>
<table name="files" />
</tables>
<columns distinct="distinct">
<column name="module_srl" />
</columns>
</query>
</conditions>
</query>

View file

@ -184,8 +184,13 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<form action="./" method="get" onsubmit="return checkSearch(this)" class="search center x_input-append">
<input type="hidden" name="module" value="{$module}" />
<input type="hidden" name="act" value="{$act}" />
<input type="hidden" name="module_srl" value="{$module_srl}" />
<input type="hidden" name="error_return_url" value="" />
<select name="module_srl" style="margin-right:4px">
<option value="">{lang('all')}</option>
<!--@foreach($module_list as $item)-->
<option value="{$item->module_srl}" <!--@if(isset($module_srl) && $module_srl == $item->module_srl)-->selected="selected"<!--@end-->>{$item->browser_title}</option>
<!--@endforeach-->
</select>
<select name="search_target" title="{$lang->search_target}" style="margin-right:4px">
<!--@foreach(lang('file.file_search_target_list') as $key => $val)-->
<option value="{$key}" <!--@if($search_target==$key)-->selected="selected"<!--@end-->>{$val}</option>

View file

@ -82,7 +82,7 @@
<div cond="$var->type == 'textarea'">
{@$use_multilang_textarea = true}
<textarea name="{$name}" rows="4" cols="42" class="lang_code"><!--@if(strpos($var->value, "$user_lang->") !== false)-->{htmlspecialchars($var->value, ENT_COMPAT | ENT_HTML401, 'UTF-8', false)}<!--@else-->{$var->value}<!--@end--></textarea>
<textarea name="{$name}" rows="4" cols="42" class="x_full-width lang_code"><!--@if(strpos($var->value, "$user_lang->") !== false)-->{htmlspecialchars($var->value, ENT_COMPAT | ENT_HTML401, 'UTF-8', false)}<!--@else-->{$var->value}<!--@end--></textarea>
</div>
<block cond="$var->type == 'image'">

View file

@ -80,6 +80,10 @@ class MemberAdminController extends Member
{
$output = executeQuery('member.getMemberInfoByMemberSrl', ['member_srl' => $args->member_srl], ['extra_vars']);
$extra_vars = ($output->data && $output->data->extra_vars) ? unserialize($output->data->extra_vars) : new stdClass;
if (!is_object($extra_vars))
{
$extra_vars = new stdClass;
}
foreach(self::NOUSE_EXTRA_VARS as $key)
{
unset($extra_vars->$key);

View file

@ -1820,23 +1820,13 @@ class MemberController extends Member
Context::set('auth_args', $args);
$memberInfo = array();
if(is_array($member_config->signupForm))
if (in_array('user_id', $member_config->identifiers))
{
$exceptForm=array('password', 'find_account_question');
foreach($member_config->signupForm as $form)
{
if(!in_array($form->name, $exceptForm) && $form->isDefaultForm && ($form->required || $form->mustRequired))
{
$memberInfo[$lang->{$form->name}] = $member_info->{$form->name};
$memberInfo[$lang->user_id] = $member_info->user_id;
}
}
}
else
if (in_array('email_address', $member_config->identifiers))
{
$memberInfo[$lang->user_id] = $args->user_id;
$memberInfo[$lang->user_name] = $args->user_name;
$memberInfo[$lang->nick_name] = $args->nick_name;
$memberInfo[$lang->email_address] = $args->email_address;
$memberInfo[$lang->email_address] = $member_info->email_address;
}
Context::set('memberInfo', $memberInfo);

View file

@ -1,7 +0,0 @@
<filter name="logout" module="member" act="procMemberLogout">
<form />
<response callback_func="completeLogout">
<tag name="error" />
<tag name="message" />
</response>
</filter>

View file

@ -1,9 +0,0 @@
<include target="./common_header.html" />
<import target="filter/logout.xml" />
<form action="./" method="get" onsubmit="return procFilter(this, logout)">
<input type="hidden" name="mid" value="{$mid}" />
<h1>{$lang->cmd_logout}</h1>
<p>{$lang->confirm_logout}</p>
<p><input type="submit" value="{$lang->cmd_logout}" class="btn btn-inverse" /></p>
</form>
<include target="./common_footer.html" />

View file

@ -2379,7 +2379,7 @@ jQuery(function($){
case 'manager':
case 'root':
default:
$node.find('._group_manager').prop('selected', true);
//$node.find('._group_manager').prop('selected', true);
$node.find('._group_all').remove();
$node.find('._group_loggedin').remove();
$node.find('._group_not_loggedin').remove();

View file

@ -16,6 +16,7 @@
<action name="procModuleFileBoxAdd" type="controller" permission="root" />
<action name="procModuleFileBoxDelete" type="controller" permission="root" />
<action name="procModuleClearCache" type="controller" check_csrf="false" />
<action name="dispModuleAdminContent" type="view" menu_name="installedModule" menu_index="true" admin_index="true" />
<action name="dispModuleAdminCategory" type="view" menu_name="installedModule" />

View file

@ -1266,6 +1266,62 @@ class ModuleController extends Module
return executeQuery('module.deleteModuleFileBox', $args);
}
/**
* API call to clear cache entries.
*
* This can be used to clear the APC cache from CLI scripts,
* such as async tasks run from crontab.
*/
public function procModuleClearCache()
{
// This is a JSON API.
Context::setResponseMethod('JSON');
if (PHP_SAPI === 'cli')
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
// Get cache keys to clear.
$keys = Context::get('keys');
if (!$keys)
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
if (!is_array($keys))
{
$keys = [$keys];
}
// Verify the API signature.
$keystring = implode('|', $keys);
$signature = Context::get('signature');
if (!$signature)
{
throw new Rhymix\Framework\Exceptions\NotPermitted;
}
if (!Rhymix\Framework\Security::verifySignature($keystring, $signature))
{
throw new Rhymix\Framework\Exceptions\NotPermitted;
}
// Clear the requested cache keys.
foreach ($keys as $key)
{
if ($key === '*')
{
Rhymix\Framework\Cache::clearAll();
}
elseif (preg_match('/^([^:]+):\*$/', $key, $matches))
{
Rhymix\Framework\Cache::clearGroup($matches[1]);
}
else
{
Rhymix\Framework\Cache::delete($key);
}
}
}
/**
* @brief function of locking (timeout is in seconds)
*/

View file

@ -93,7 +93,7 @@
<input cond="$val->type == 'text'" type="text" name="{$val->name}" id="{$val->name}" value="<!--@if(strpos($val->value ?? '', '$user_lang->') === false)-->{$val->value}<!--@else-->{htmlspecialchars($val->value, ENT_COMPAT | ENT_HTML401, 'UTF-8', false)}<!--@end-->" class="lang_code" />
<!--// textarea -->
<textarea cond="$val->type == 'textarea'" rows="8" cols="42" name="{$val->name}" id="{$val->name}" class="lang_code"><!--@if(strpos($val->value ?? '', '$user_lang->') === false)-->{$val->value}<!--@else-->{htmlspecialchars($val->value, ENT_COMPAT | ENT_HTML401, 'UTF-8', false)}<!--@end--></textarea>
<textarea cond="$val->type == 'textarea'" rows="8" cols="42" name="{$val->name}" id="{$val->name}" class="x_full-width lang_code"><!--@if(strpos($val->value ?? '', '$user_lang->') === false)-->{$val->value}<!--@else-->{htmlspecialchars($val->value, ENT_COMPAT | ENT_HTML401, 'UTF-8', false)}<!--@end--></textarea>
<!--// select -->
<select cond="$val->type == 'select'" name="{$val->name}" id="{$val->name}">

View file

@ -1,4 +1,4 @@
{'<?xml version="1.0" encoding="UTF-8" ?>'}
<?php echo '<?xml version="1.0" encoding="UTF-8" ?>'; ?>
<config autoescape="on" />
<feed xmlns="http://www.w3.org/2005/Atom">

View file

@ -1,4 +1,4 @@
{'<?xml version="1.0" encoding="UTF-8" ?>'}
<?php echo '<?xml version="1.0" encoding="UTF-8" ?>'; ?>
<config autoescape="on" />
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://purl.org/rss/1.0/">

View file

@ -1,4 +1,4 @@
{'<?xml version="1.0" encoding="UTF-8" ?>'}
<?php echo '<?xml version="1.0" encoding="UTF-8" ?>'; ?>
<config autoescape="on" />
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">

View file

@ -1,4 +1,4 @@
{'<?xml version="1.0" encoding="UTF-8" ?>'}
<?php echo '<?xml version="1.0" encoding="UTF-8" ?>'; ?>
<config autoescape="on" />
<rss version="1.0">

View file

@ -730,11 +730,6 @@ class WidgetController extends Widget
// Debug widget creation time information added to the results
$elapsed_time = microtime(true) - $start;
if (!isset($GLOBALS['__widget_excute_elapsed__']))
{
$GLOBALS['__widget_excute_elapsed__'] = 0;
}
$GLOBALS['__widget_excute_elapsed__'] += $elapsed_time;
if (Rhymix\Framework\Debug::isEnabledForCurrentUser())
{
Rhymix\Framework\Debug::addWidget(array(

View file

@ -7,5 +7,7 @@
</columns>
<conditions>
<condition operation="search" column="content" var="s_content" />
<condition operation="equal" column="COUNT(DISTINCT voted_count)" var="s_voted_count" />
<condition operation="equal" column="other_table.blamed_count" var="s_blamed_count" />
</conditions>
</query>

View file

@ -132,6 +132,23 @@ class DBQueryParserTest extends \Codeception\Test\Unit
$this->assertEquals(['%검색%', '%키워드%', '%라이믹스 유닛테스트%'], $params);
}
public function testQuoteName()
{
$query = Rhymix\Framework\Parsers\DBQueryParser::loadXML(\RX_BASEDIR . 'tests/_data/dbquery/selectTest3.xml');
$args = array('s_voted_count' => 24);
$sql = $query->getQueryString('rx_', $args);
$params = $query->getQueryParams();
$this->assertEquals('SELECT * FROM `rx_documents` AS `documents` WHERE COUNT(DISTINCT `voted_count`) = ?', $sql);
$this->assertEquals([24], $params);
$args = array('s_blamed_count' => 42);
$sql = $query->getQueryString('rx_', $args);
$params = $query->getQueryParams();
$this->assertEquals('SELECT * FROM `rx_documents` AS `documents` WHERE `other_table`.`blamed_count` = ?', $sql);
$this->assertEquals([42], $params);
}
public function testJoin1()
{
$query = Rhymix\Framework\Parsers\DBQueryParser::loadXML(\RX_BASEDIR . 'tests/_data/dbquery/selectJoinTest1.xml');

View file

@ -446,9 +446,19 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
$target = "<?php echo nl2br(htmlspecialchars(\$__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false)); ?>";
$this->assertEquals($target, $this->_parse($source));
// nl2br() with gratuitous escape
// nl2br() with extra escape
$source = '{{ $foo|nl2br|escape }}';
$target = "<?php echo htmlspecialchars(nl2br(htmlspecialchars(\$__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false)), \ENT_QUOTES, 'UTF-8', true); ?>";
$target = "<?php echo nl2br(htmlspecialchars(\$__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', true)); ?>";
$this->assertEquals($target, $this->_parse($source));
// nl2br() with noescape
$source = '{{ $foo|nl2br|noescape }}';
$target = "<?php echo nl2br(\$__Context->foo ?? ''); ?>";
$this->assertEquals($target, $this->_parse($source));
// nl2br() with noescape and autoescape
$source = '{{ $foo|noescape|nl2br|autoescape }}';
$target = "<?php echo nl2br(htmlspecialchars(\$__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false)); ?>";
$this->assertEquals($target, $this->_parse($source));
// Array join (default joiner is comma)
@ -1105,6 +1115,40 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
'',
]);
$this->assertEquals($target, $this->_parse($source));
// @verbatim block inside @php block
$source = implode("\n", [
'@php',
'@verbatim',
'$foo = $bar->$baz;',
'@endverbatim',
'@endphp',
]);
$target = implode("\n", [
'<?php',
'',
'$foo = $bar->$baz;',
'',
'?>',
]);
$this->assertEquals($target, $this->_parse($source));
// @php block inside @verbatim block
$source = implode("\n", [
'@verbatim',
'@php',
'$foo = $bar->$baz;',
'@endphp',
'@endverbatim',
]);
$target = implode("\n", [
'',
'@php',
'$foo = $bar->$baz;',
'@endphp',
'',
]);
$this->assertEquals($target, $this->_parse($source));
}
public function testRawPhpCode()