Browse Source

first commit

liuhairui 9 months ago
parent
commit
d639ae31bf
100 changed files with 1331 additions and 928 deletions
  1. 1 0
      thinkphp/.gitignore
  2. 1 1
      thinkphp/README.md
  3. 1 1
      thinkphp/base.php
  4. 1 1
      thinkphp/library/think/App.php
  5. 9 2
      thinkphp/library/think/Collection.php
  6. 1 1
      thinkphp/library/think/Controller.php
  7. 19 7
      thinkphp/library/think/Cookie.php
  8. 1 1
      thinkphp/library/think/Lang.php
  9. 1 1
      thinkphp/library/think/Loader.php
  10. 28 3
      thinkphp/library/think/Model.php
  11. 8 1
      thinkphp/library/think/Paginator.php
  12. 12 7
      thinkphp/library/think/Request.php
  13. 2 2
      thinkphp/library/think/Template.php
  14. 25 3
      thinkphp/library/think/Validate.php
  15. 1 1
      thinkphp/library/think/console/Command.php
  16. 1 1
      thinkphp/library/think/console/output/Ask.php
  17. 2 2
      thinkphp/library/think/console/output/Descriptor.php
  18. 2 2
      thinkphp/library/think/console/output/formatter/Stack.php
  19. 3 3
      thinkphp/library/think/db/Connection.php
  20. 2 1
      thinkphp/library/think/db/Query.php
  21. 1 5
      thinkphp/library/think/db/builder/Mysql.php
  22. 1 2
      thinkphp/library/think/db/builder/Sqlsrv.php
  23. 1 1
      thinkphp/library/think/exception/HttpException.php
  24. 1 1
      thinkphp/library/think/model/relation/HasMany.php
  25. 1 1
      thinkphp/library/think/model/relation/MorphOne.php
  26. 2 1
      thinkphp/library/think/model/relation/MorphTo.php
  27. 7 1
      thinkphp/library/think/session/driver/Redis.php
  28. 2 2
      thinkphp/library/traits/controller/Jump.php
  29. 2 2
      thinkphp/tpl/think_exception.tpl
  30. 2 15
      vendor/autoload.php
  31. 14 27
      vendor/composer/ClassLoader.php
  32. 5 12
      vendor/composer/InstalledVersions.php
  33. 3 2
      vendor/composer/autoload_psr4.php
  34. 17 10
      vendor/composer/autoload_real.php
  35. 9 4
      vendor/composer/autoload_static.php
  36. 220 186
      vendor/composer/installed.json
  37. 73 64
      vendor/composer/installed.php
  38. 0 6
      vendor/ezyang/htmlpurifier/CHANGELOG.md
  39. 1 1
      vendor/ezyang/htmlpurifier/VERSION
  40. 3 2
      vendor/ezyang/htmlpurifier/composer.json
  41. 2 1
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php
  42. 3 3
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.php
  43. 1 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php
  44. 9 5
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php
  45. 15 17
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php
  46. 46 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ratio.php
  47. 7 13
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php
  48. 5 1
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php
  49. 4 37
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php
  50. 112 96
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php
  51. 3 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php
  52. 1 1
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php
  53. 0 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser
  54. 10 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveBlanks.txt
  55. 6 5
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php
  56. 1 1
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php
  57. 2 2
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php
  58. 172 151
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php
  59. 17 11
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php
  60. 1 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy.php
  61. 1 1
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/LanguageFactory.php
  62. 1 17
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer.php
  63. 3 1
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php
  64. 5 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php
  65. 1 1
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Tag.php
  66. 3 3
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/tel.php
  67. 3 3
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php
  68. 65 2
      vendor/guzzlehttp/guzzle/CHANGELOG.md
  69. 6 6
      vendor/guzzlehttp/guzzle/README.md
  70. 8 8
      vendor/guzzlehttp/guzzle/UPGRADING.md
  71. 33 5
      vendor/guzzlehttp/guzzle/composer.json
  72. 3 3
      vendor/guzzlehttp/guzzle/src/BodySummarizer.php
  73. 1 1
      vendor/guzzlehttp/guzzle/src/Client.php
  74. 13 25
      vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
  75. 1 0
      vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
  76. 6 2
      vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
  77. 1 1
      vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
  78. 1 1
      vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php
  79. 6 22
      vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
  80. 130 24
      vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
  81. 24 3
      vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
  82. 4 4
      vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
  83. 6 6
      vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
  84. 17 5
      vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
  85. 1 1
      vendor/guzzlehttp/guzzle/src/HandlerStack.php
  86. 3 3
      vendor/guzzlehttp/guzzle/src/Middleware.php
  87. 1 1
      vendor/guzzlehttp/guzzle/src/Pool.php
  88. 2 2
      vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
  89. 2 2
      vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
  90. 2 4
      vendor/guzzlehttp/guzzle/src/RequestOptions.php
  91. 2 2
      vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
  92. 10 11
      vendor/guzzlehttp/guzzle/src/Utils.php
  93. 1 1
      vendor/guzzlehttp/guzzle/src/functions.php
  94. 43 1
      vendor/guzzlehttp/promises/CHANGELOG.md
  95. 4 4
      vendor/guzzlehttp/promises/README.md
  96. 2 2
      vendor/guzzlehttp/promises/composer.json
  97. 2 2
      vendor/guzzlehttp/promises/src/Coroutine.php
  98. 6 11
      vendor/guzzlehttp/promises/src/Each.php
  99. 3 5
      vendor/guzzlehttp/promises/src/EachPromise.php
  100. 2 2
      vendor/guzzlehttp/promises/src/FulfilledPromise.php

+ 1 - 0
thinkphp/.gitignore

@@ -2,3 +2,4 @@
 /vendor
 .idea
 .DS_Store
+/.vscode

+ 1 - 1
thinkphp/README.md

@@ -60,7 +60,7 @@ ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
 
 本项目包含的第三方源码和二进制文件之版权信息另行标注。
 
-版权所有Copyright © 2006-2022 by ThinkPHP (http://thinkphp.cn)
+版权所有Copyright © 2006-2024 by ThinkPHP (http://thinkphp.cn)
 
 All rights reserved。
 

+ 1 - 1
thinkphp/base.php

@@ -9,7 +9,7 @@
 // | Author: liu21st <liu21st@gmail.com>
 // +----------------------------------------------------------------------
 
-define('THINK_VERSION', '5.0.25');
+define('THINK_VERSION', '5.0.28');
 define('THINK_START_TIME', microtime(true));
 define('THINK_START_MEM', memory_get_usage());
 define('EXT', '.php');

+ 1 - 1
thinkphp/library/think/App.php

@@ -74,7 +74,7 @@ class App
      * @return Response
      * @throws Exception
      */
-    public static function run(Request $request = null)
+    public static function run(?Request $request = null)
     {
         $request = is_null($request) ? Request::instance() : $request;
 

+ 9 - 2
thinkphp/library/think/Collection.php

@@ -263,7 +263,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
      * @param callable|null $callback 回调函数
      * @return static
      */
-    public function filter(callable $callback = null)
+    public function filter(?callable $callback = null)
     {
         return new static(array_filter($this->items, $callback ?: null));
     }
@@ -317,7 +317,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
      * @param  callable|null $callback 回调函数
      * @return static
      */
-    public function sort(callable $callback = null)
+    public function sort(?callable $callback = null)
     {
         $items    = $this->items;
         $callback = $callback ?: function ($a, $b) {
@@ -360,6 +360,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
      * @param  mixed $offset 键名
      * @return bool
      */
+    #[\ReturnTypeWillChange]
     public function offsetExists($offset)
     {
         return array_key_exists($offset, $this->items);
@@ -371,6 +372,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
      * @param  mixed $offset 键名
      * @return mixed
      */
+    #[\ReturnTypeWillChange]
     public function offsetGet($offset)
     {
         return $this->items[$offset];
@@ -383,6 +385,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
      * @param  mixed $value  值
      * @return void
      */
+    #[\ReturnTypeWillChange]
     public function offsetSet($offset, $value)
     {
         if (is_null($offset)) {
@@ -398,6 +401,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
      * @param  mixed $offset 键名
      * @return void
      */
+    #[\ReturnTypeWillChange]
     public function offsetUnset($offset)
     {
         unset($this->items[$offset]);
@@ -408,6 +412,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
      * @access public
      * @return int
      */
+    #[\ReturnTypeWillChange]
     public function count()
     {
         return count($this->items);
@@ -418,6 +423,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
      * @access public
      * @return ArrayIterator
      */
+    #[\ReturnTypeWillChange]
     public function getIterator()
     {
         return new ArrayIterator($this->items);
@@ -428,6 +434,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
      * @access public
      * @return array
      */
+    #[\ReturnTypeWillChange]
     public function jsonSerialize()
     {
         return $this->toArray();

+ 1 - 1
thinkphp/library/think/Controller.php

@@ -50,7 +50,7 @@ class Controller
      * @access public
      * @param Request $request Request 对象
      */
-    public function __construct(Request $request = null)
+    public function __construct(?Request $request = null)
     {
         $this->view    = View::instance(Config::get('template'), Config::get('view_replace_str'));
         $this->request = is_null($request) ? Request::instance() : $request;

+ 19 - 7
thinkphp/library/think/Cookie.php

@@ -45,7 +45,7 @@ class Cookie
 
         self::$config = array_merge(self::$config, array_change_key_case($config));
 
-        if (!empty(self::$config['httponly'])) {
+        if (!empty(self::$config['httponly']) && PHP_SESSION_ACTIVE != session_status()) {
             ini_set('session.cookie_httponly', 1);
         }
 
@@ -101,14 +101,26 @@ class Cookie
         }
 
         $expire = !empty($config['expire']) ?
-        $_SERVER['REQUEST_TIME'] + intval($config['expire']) :
-        0;
+            $_SERVER['REQUEST_TIME'] + intval($config['expire']) :
+            0;
 
         if ($config['setcookie']) {
-            setcookie(
-                $name, $value, $expire, $config['path'], $config['domain'],
-                $config['secure'], $config['httponly']
-            );
+            if (PHP_VERSION_ID >= 70300) {
+                // PHP 7.3+ 支持选项数组
+                setcookie($name, $value, array_merge([
+                    'expires'  => $expire,
+                    'path'     => $config['path'],
+                    'domain'   => $config['domain'],
+                    'secure'   => $config['secure'],
+                    'httponly' => $config['httponly']
+                ], isset($config['samesite']) ? ['samesite' => $config['samesite']] : []));
+            } else {
+                // 旧版本 PHP 使用传统参数方式
+                setcookie(
+                    $name, $value, $expire, $config['path'], $config['domain'],
+                    $config['secure'], $config['httponly']
+                );
+            }
         }
 
         $_COOKIE[$name] = $value;

+ 1 - 1
thinkphp/library/think/Lang.php

@@ -201,7 +201,7 @@ class Lang
         } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
             // 自动侦测浏览器语言
             preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
-            $langSet     = strtolower($matches[1]);
+            $langSet     = strtolower($matches[1] ?? '');
             $acceptLangs = Config::get('header_accept_lang');
 
             if (isset($acceptLangs[$langSet])) {

+ 1 - 1
thinkphp/library/think/Loader.php

@@ -613,7 +613,7 @@ class Loader
         if ($type) {
             $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
                 return strtoupper($match[1]);
-            }, $name);
+            }, $name ?? '');
 
             return $ucfirst ? ucfirst($name) : lcfirst($name);
         }

+ 28 - 3
thinkphp/library/think/Model.php

@@ -537,6 +537,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
             list($type, $param) = explode(':', $type, 2);
         }
         switch ($type) {
+            case 'string':
+            case 'bigint':
+                $value = (string) $value;
+                break;
+            case 'int':
             case 'integer':
                 $value = (int) $value;
                 break;
@@ -547,6 +552,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
                     $value = (float) number_format($value, $param, '.', '');
                 }
                 break;
+            case 'bool':
             case 'boolean':
                 $value = (bool) $value;
                 break;
@@ -670,6 +676,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
             list($type, $param) = explode(':', $type, 2);
         }
         switch ($type) {
+            case 'string':
+            case 'bigint':
+                $value = (string) $value;
+                break;
+            case 'int':
             case 'integer':
                 $value = (int) $value;
                 break;
@@ -680,6 +691,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
                     $value = (float) number_format($value, $param, '.', '');
                 }
                 break;
+            case 'bool':
             case 'boolean':
                 $value = (bool) $value;
                 break;
@@ -1267,10 +1279,18 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
             $data = $this->data;
         } else {
             $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
+                if (is_numeric($a) && is_numeric($b)) {
+                    if (strcmp($a, $b) !== 0) {
+                        return 1;
+                    }
+                    if ($a == $b) {
+                        return 0;
+                    }
+                }
                 if ((empty($a) || empty($b)) && $a !== $b) {
                     return 1;
                 }
-                return is_object($a) || $a != $b ? 1 : 0;
+                return is_object($a) || $a !== $b ? 1 : 0;
             });
         }
 
@@ -1309,10 +1329,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     }
 
     /**
-     * 字段值(延迟)增长
+     * 字段值(延迟)减少
      * @access public
      * @param string  $field    字段名
-     * @param integer $step     增长
+     * @param integer $step     减少
      * @param integer $lazyTime 延时时间(s)
      * @return integer|true
      * @throws Exception
@@ -2268,27 +2288,32 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     }
 
     // JsonSerializable
+    #[\ReturnTypeWillChange]
     public function jsonSerialize()
     {
         return $this->toArray();
     }
 
     // ArrayAccess
+    #[\ReturnTypeWillChange]
     public function offsetSet($name, $value)
     {
         $this->setAttr($name, $value);
     }
 
+    #[\ReturnTypeWillChange]
     public function offsetExists($name)
     {
         return $this->__isset($name);
     }
 
+    #[\ReturnTypeWillChange]
     public function offsetUnset($name)
     {
         $this->__unset($name);
     }
 
+    #[\ReturnTypeWillChange]
     public function offsetGet($name)
     {
         return $this->getAttr($name);

+ 8 - 1
thinkphp/library/think/Paginator.php

@@ -128,7 +128,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
         }
         $url = $path;
         if (!empty($parameters)) {
-            $url .= '?' . http_build_query($parameters, null, '&');
+            $url .= '?' . http_build_query($parameters, '', '&');
         }
         return $url . $this->buildFragment();
     }
@@ -304,6 +304,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
      * @return Traversable An instance of an object implementing <b>Iterator</b> or
      * <b>Traversable</b>
      */
+    #[\ReturnTypeWillChange]
     public function getIterator()
     {
         return new ArrayIterator($this->items->all());
@@ -314,6 +315,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
      * @param mixed $offset
      * @return bool
      */
+    #[\ReturnTypeWillChange]
     public function offsetExists($offset)
     {
         return $this->items->offsetExists($offset);
@@ -324,6 +326,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
      * @param mixed $offset
      * @return mixed
      */
+    #[\ReturnTypeWillChange]
     public function offsetGet($offset)
     {
         return $this->items->offsetGet($offset);
@@ -334,6 +337,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
      * @param mixed $offset
      * @param mixed $value
      */
+    #[\ReturnTypeWillChange]
     public function offsetSet($offset, $value)
     {
         $this->items->offsetSet($offset, $value);
@@ -345,6 +349,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
      * @return void
      * @since 5.0.0
      */
+    #[\ReturnTypeWillChange]
     public function offsetUnset($offset)
     {
         $this->items->offsetUnset($offset);
@@ -353,6 +358,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
     /**
      * Count elements of an object
      */
+    #[\ReturnTypeWillChange]
     public function count()
     {
         return $this->items->count();
@@ -388,6 +394,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
     /**
      * Specify data which should be serialized to JSON
      */
+    #[\ReturnTypeWillChange]
     public function jsonSerialize()
     {
         return $this->toArray();

+ 12 - 7
thinkphp/library/think/Request.php

@@ -521,19 +521,24 @@ class Request
             // 获取原始请求类型
             return $this->server('REQUEST_METHOD') ?: 'GET';
         } elseif (!$this->method) {
-            if (isset($_POST[Config::get('var_method')])) {
-                $method = strtoupper($_POST[Config::get('var_method')]);
+            $varMethod = Config::get('var_method');
+            if ($varMethod && isset($_POST[$varMethod])) {
+                $method = strtoupper($_POST[$varMethod]);
                 if (in_array($method, ['GET', 'POST', 'DELETE', 'PUT', 'PATCH'])) {
                     $this->method = $method;
                     $this->{$this->method}($_POST);
                 } else {
                     $this->method = 'POST';
                 }
-                unset($_POST[Config::get('var_method')]);
-            } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
-                $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
+                unset($_POST[$varMethod]);
             } else {
-                $this->method = $this->server('REQUEST_METHOD') ?: 'GET';
+                $method = $this->server('REQUEST_METHOD') ?: 'GET';
+                $httpMethodOverride = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ?? '');
+                if ($method === 'POST' && in_array($httpMethodOverride, ['GET', 'POST', 'DELETE', 'PUT', 'PATCH'])) {
+                    $this->method = $httpMethodOverride;
+                } else {
+                    $this->method = $method;
+                }
             }
         }
         return $this->method;
@@ -1091,7 +1096,7 @@ class Request
         foreach ($filters as $filter) {
             if (is_callable($filter)) {
                 // 调用函数或者方法过滤
-                $value = call_user_func($filter, $value);
+                $value = call_user_func($filter, $value ?? '');
             } elseif (is_scalar($value)) {
                 if (false !== strpos($filter, '/')) {
                     // 正则过滤

+ 2 - 2
thinkphp/library/think/Template.php

@@ -925,11 +925,11 @@ class Template
                                     $args[1] = str_replace('###', $name, $args[1]);
                                     $name    = "$fun($args[1])";
                                 } else {
-                                    $name = "$fun($name,$args[1])";
+                                    $name = "$fun($name ?? '',$args[1])";
                                 }
                             } else {
                                 if (!empty($args[0])) {
-                                    $name = "$fun($name)";
+                                    $name = "$fun($name ?? '')";
                                 }
                             }
                         }

+ 25 - 3
thinkphp/library/think/Validate.php

@@ -37,11 +37,13 @@ class Validate
     // 验证规则默认提示信息
     protected static $typeMsg = [
         'require'     => ':attribute require',
+        'must'        => ':attribute must',
         'number'      => ':attribute must be numeric',
         'integer'     => ':attribute must be integer',
         'float'       => ':attribute must be float',
         'boolean'     => ':attribute must be bool',
         'email'       => ':attribute not a valid email address',
+        'mobile'      => ':attribute not a valid mobile',
         'array'       => ':attribute must be a array',
         'accepted'    => ':attribute must be yes,on or 1',
         'date'        => ':attribute not a valid datetime',
@@ -91,6 +93,23 @@ class Validate
     // 当前验证场景
     protected $currentScene = null;
 
+    /**
+     * 内置正则验证规则
+     * @var array
+     */
+    protected $defaultRegex = [
+        'alpha'       => '/^[A-Za-z]+$/',
+        'alphaNum'    => '/^[A-Za-z0-9]+$/',
+        'alphaDash'   => '/^[A-Za-z0-9\-\_]+$/',
+        'chs'         => '/^[\x{4e00}-\x{9fa5}\x{9fa6}-\x{9fef}\x{3400}-\x{4db5}\x{20000}-\x{2ebe0}]+$/u',
+        'chsAlpha'    => '/^[\x{4e00}-\x{9fa5}\x{9fa6}-\x{9fef}\x{3400}-\x{4db5}\x{20000}-\x{2ebe0}a-zA-Z]+$/u',
+        'chsAlphaNum' => '/^[\x{4e00}-\x{9fa5}\x{9fa6}-\x{9fef}\x{3400}-\x{4db5}\x{20000}-\x{2ebe0}a-zA-Z0-9]+$/u',
+        'chsDash'     => '/^[\x{4e00}-\x{9fa5}\x{9fa6}-\x{9fef}\x{3400}-\x{4db5}\x{20000}-\x{2ebe0}a-zA-Z0-9\_\-]+$/u',
+        'mobile'      => '/^1[3-9]\d{9}$/',
+        'idCard'      => '/(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/',
+        'zip'         => '/\d{6}/',
+    ];
+
     // 正则表达式 regex = ['zip'=>'\d{6}',...]
     protected $regex = [];
 
@@ -931,10 +950,10 @@ class Validate
         if (is_string($rule) && strpos($rule, ',')) {
             list($rule, $param) = explode(',', $rule);
         } elseif (is_array($rule)) {
-            $param = isset($rule[1]) ? $rule[1] : null;
+            $param = $rule[1] ?? 0;
             $rule  = $rule[0];
         } else {
-            $param = null;
+            $param = 0;
         }
         return false !== filter_var($value, is_int($rule) ? $rule : filter_id($rule), $param);
     }
@@ -1226,8 +1245,11 @@ class Validate
     {
         if (isset($this->regex[$rule])) {
             $rule = $this->regex[$rule];
+        } elseif (isset($this->defaultRegex[$rule])) {
+            $rule = $this->defaultRegex[$rule];
         }
-        if (0 !== strpos($rule, '/') && !preg_match('/\/[imsU]{0,4}$/', $rule)) {
+
+        if (is_string($rule) && 0 !== strpos($rule, '/') && !preg_match('/\/[imsU]{0,4}$/', $rule)) {
             // 不是正则表达式则两端补上/
             $rule = '/^' . $rule . '$/';
         }

+ 1 - 1
thinkphp/library/think/console/Command.php

@@ -72,7 +72,7 @@ class Command
      * 设置控制台
      * @param Console $console
      */
-    public function setConsole(Console $console = null)
+    public function setConsole(?Console $console = null)
     {
         $this->console = $console;
     }

+ 1 - 1
thinkphp/library/think/console/output/Ask.php

@@ -299,7 +299,7 @@ class Ask
             $width = max(array_map('strlen', array_keys($this->question->getChoices())));
 
             foreach ($this->question->getChoices() as $key => $value) {
-                $this->output->writeln(sprintf("  [<comment>%-${width}s</comment>] %s", $key, $value));
+                $this->output->writeln(sprintf("  [<comment>%-{$width}s</comment>] %s", $key, $value));
             }
         }
 

+ 2 - 2
thinkphp/library/think/console/output/Descriptor.php

@@ -155,7 +155,7 @@ class Descriptor
 
             $this->writeText('<comment>Options:</comment>', $options);
             foreach ($definition->getOptions() as $option) {
-                if (strlen($option->getShortcut()) > 1) {
+                if ($option->getShortcut() && strlen($option->getShortcut()) > 1) {
                     $laterOptions[] = $option;
                     continue;
                 }
@@ -219,7 +219,7 @@ class Descriptor
             $width = $this->getColumnWidth($description->getCommands());
 
             foreach ($description->getCommands() as $command) {
-                $this->writeText(sprintf("%-${width}s %s", $command->getName(), $command->getDescription()), $options);
+                $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
                 $this->writeText("\n");
             }
         } else {

+ 2 - 2
thinkphp/library/think/console/output/formatter/Stack.php

@@ -28,7 +28,7 @@ class Stack
      * 构造方法
      * @param Style|null $emptyStyle
      */
-    public function __construct(Style $emptyStyle = null)
+    public function __construct(?Style $emptyStyle = null)
     {
         $this->emptyStyle = $emptyStyle ?: new Style();
         $this->reset();
@@ -57,7 +57,7 @@ class Stack
      * @return Style
      * @throws \InvalidArgumentException
      */
-    public function pop(Style $style = null)
+    public function pop(?Style $style = null)
     {
         if (empty($this->styles)) {
             return $this->emptyStyle;

+ 3 - 3
thinkphp/library/think/db/Connection.php

@@ -406,7 +406,7 @@ abstract class Connection
      * @throws PDOException
      * @throws \Exception
      */
-    public function execute($sql, $bind = [], Query $query = null)
+    public function execute($sql, $bind = [], ?Query $query = null)
     {
         $this->initConnect(true);
         if (!$this->linkID) {
@@ -483,7 +483,7 @@ abstract class Connection
             if (PDO::PARAM_STR == $type) {
                 $value = $this->quote($value);
             } elseif (PDO::PARAM_INT == $type) {
-                $value = (float) $value;
+                $value = sprintf("%d", $value);
             }
             // 判断占位符
             $sql = is_numeric($key) ?
@@ -738,7 +738,7 @@ abstract class Connection
      * @param array $sqlArray SQL批处理指令
      * @return boolean
      */
-    public function batchQuery($sqlArray = [], $bind = [], Query $query = null)
+    public function batchQuery($sqlArray = [], $bind = [], ?Query $query = null)
     {
         if (!is_array($sqlArray)) {
             return false;

+ 2 - 1
thinkphp/library/think/db/Query.php

@@ -62,7 +62,7 @@ class Query
      * @param Connection $connection 数据库对象实例
      * @param Model      $model      模型对象
      */
-    public function __construct(Connection $connection = null, $model = null)
+    public function __construct(?Connection $connection = null, $model = null)
     {
         $this->connection = $connection ?: Db::connect([], true);
         $this->prefix     = $this->connection->getConfig('prefix');
@@ -480,6 +480,7 @@ class Query
             $result = Cache::get($guid);
         }
         if (false === $result) {
+            $result = [];
             if (isset($this->options['field'])) {
                 unset($this->options['field']);
             }

+ 1 - 5
thinkphp/library/think/db/builder/Mysql.php

@@ -109,12 +109,8 @@ class Mysql extends Builder
             }
         }
 
-//        if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) {
-//            throw new Exception('not support data:' . $key);
-//        }
-        if ($strict && !preg_match('/^[\w\.\*\x00-\xff]+$/', $key)) {
+        if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) {
             throw new Exception('not support data:' . $key);
-
         }
         if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key))) {
             $key = '`' . $key . '`';

+ 1 - 2
thinkphp/library/think/db/builder/Sqlsrv.php

@@ -13,7 +13,6 @@ namespace think\db\builder;
 
 use think\db\Builder;
 use think\db\Expression;
-use think\Exception;
 
 /**
  * Sqlsrv数据库驱动
@@ -96,7 +95,7 @@ class Sqlsrv extends Builder
             }
         }
 
-        if ($strict && !preg_match('/^[\w\.\*\x7f-\xff]+$/', $key)) {
+        if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) {
             throw new Exception('not support data:' . $key);
         }
         if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key))) {

+ 1 - 1
thinkphp/library/think/exception/HttpException.php

@@ -16,7 +16,7 @@ class HttpException extends \RuntimeException
     private $statusCode;
     private $headers;
 
-    public function __construct($statusCode, $message = null, \Exception $previous = null, array $headers = [], $code = 0)
+    public function __construct($statusCode, $message = null, ?\Exception $previous = null, array $headers = [], $code = 0)
     {
         $this->statusCode = $statusCode;
         $this->headers    = $headers;

+ 1 - 1
thinkphp/library/think/model/relation/HasMany.php

@@ -164,7 +164,7 @@ class HasMany extends Relation
             }
         }
         $localKey = $this->localKey ?: $this->parent->getPk();
-        return $this->query->whereExp($this->foreignKey, '=' . $this->parent->getTable() . '.' . $localKey)->fetchSql()->count();
+        return $this->query->alias( 'count_table')->whereExp( 'count_table.' . $this->foreignKey, '=' . $this->parent->getTable() . '.' . $localKey)->fetchSql()->count();
     }
 
     /**

+ 1 - 1
thinkphp/library/think/model/relation/MorphOne.php

@@ -211,7 +211,7 @@ class MorphOne extends Relation
 
         $model = new $this->model();
 
-        return $model->save() ? $model : false;
+        return $model->save($data) ? $model : false;
     }
 
     /**

+ 2 - 1
thinkphp/library/think/model/relation/MorphTo.php

@@ -137,10 +137,11 @@ class MorphTo extends Relation
 
     /**
      * 移除关联查询参数
+     * @param true $option
      * @access public
      * @return $this
      */
-    public function removeOption()
+    public function removeOption($option = true)
     {
         return $this;
     }

+ 7 - 1
thinkphp/library/think/session/driver/Redis.php

@@ -42,6 +42,7 @@ class Redis extends SessionHandler
      * @return bool
      * @throws Exception
      */
+    #[\ReturnTypeWillChange]
     public function open($savePath, $sessName)
     {
         // 检测php环境
@@ -69,6 +70,7 @@ class Redis extends SessionHandler
      * 关闭Session
      * @access public
      */
+    #[\ReturnTypeWillChange]
     public function close()
     {
         $this->gc(ini_get('session.gc_maxlifetime'));
@@ -83,6 +85,7 @@ class Redis extends SessionHandler
      * @param string $sessID
      * @return string
      */
+    #[\ReturnTypeWillChange]
     public function read($sessID)
     {
         return (string) $this->handler->get($this->config['session_name'] . $sessID);
@@ -92,9 +95,10 @@ class Redis extends SessionHandler
      * 写入Session
      * @access public
      * @param string $sessID
-     * @param String $sessData
+     * @param string $sessData
      * @return bool
      */
+    #[\ReturnTypeWillChange]
     public function write($sessID, $sessData)
     {
         if ($this->config['expire'] > 0) {
@@ -110,6 +114,7 @@ class Redis extends SessionHandler
      * @param string $sessID
      * @return bool
      */
+    #[\ReturnTypeWillChange]
     public function destroy($sessID)
     {
         return $this->handler->del($this->config['session_name'] . $sessID) > 0;
@@ -121,6 +126,7 @@ class Redis extends SessionHandler
      * @param string $sessMaxLifeTime
      * @return bool
      */
+    #[\ReturnTypeWillChange]
     public function gc($sessMaxLifeTime)
     {
         return true;

+ 2 - 2
thinkphp/library/traits/controller/Jump.php

@@ -38,8 +38,8 @@ trait Jump
     {
         if (is_null($url) && !is_null(Request::instance()->server('HTTP_REFERER'))) {
             $url = Request::instance()->server('HTTP_REFERER');
-        } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) {
-            $url = Url::build($url);
+        } elseif ('' !== $url && !strpos($url ?? '', '://') && 0 !== strpos($url ?? '', '/')) {
+            $url = Url::build($url ?? '');
         }
 
         $type = $this->getResponseType();

+ 2 - 2
thinkphp/tpl/think_exception.tpl

@@ -68,7 +68,7 @@
                         break;
                 }
 
-                $result[] = is_int($key) ? $value : "'{$key}' => {$value}";
+                $result[] = is_int($key) ? $value : sprintf('\'%s\' => %s', htmlentities($key), $value);
             }
 
             return implode(', ', $result);
@@ -519,7 +519,7 @@
             var err_line = $('.line-' + LINE, ol[0])[0];
             err_line.className = err_line.className + ' line-error';
 
-            $.getScript('//cdn.bootcss.com/prettify/r298/prettify.min.js', function(){
+            $.getScript('//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/prettify/r298/prettify.min.js', function(){
                 prettyPrint();
 
                 // 解决Firefox浏览器一个很诡异的问题

+ 2 - 15
vendor/autoload.php

@@ -3,21 +3,8 @@
 // autoload.php @generated by Composer
 
 if (PHP_VERSION_ID < 50600) {
-    if (!headers_sent()) {
-        header('HTTP/1.1 500 Internal Server Error');
-    }
-    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
-    if (!ini_get('display_errors')) {
-        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
-            fwrite(STDERR, $err);
-        } elseif (!headers_sent()) {
-            echo $err;
-        }
-    }
-    trigger_error(
-        $err,
-        E_USER_ERROR
-    );
+    echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+    exit(1);
 }
 
 require_once __DIR__ . '/composer/autoload_real.php';

+ 14 - 27
vendor/composer/ClassLoader.php

@@ -42,9 +42,6 @@ namespace Composer\Autoload;
  */
 class ClassLoader
 {
-    /** @var \Closure(string):void */
-    private static $includeFile;
-
     /** @var ?string */
     private $vendorDir;
 
@@ -109,7 +106,6 @@ class ClassLoader
     public function __construct($vendorDir = null)
     {
         $this->vendorDir = $vendorDir;
-        self::initializeIncludeClosure();
     }
 
     /**
@@ -429,8 +425,7 @@ class ClassLoader
     public function loadClass($class)
     {
         if ($file = $this->findFile($class)) {
-            $includeFile = self::$includeFile;
-            $includeFile($file);
+            includeFile($file);
 
             return true;
         }
@@ -560,26 +555,18 @@ class ClassLoader
 
         return false;
     }
+}
 
-    /**
-     * @return void
-     */
-    private static function initializeIncludeClosure()
-    {
-        if (self::$includeFile !== null) {
-            return;
-        }
-
-        /**
-         * Scope isolated include.
-         *
-         * Prevents access to $this/self from included files.
-         *
-         * @param  string $file
-         * @return void
-         */
-        self::$includeFile = \Closure::bind(static function($file) {
-            include $file;
-        }, null, null);
-    }
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ *
+ * @param  string $file
+ * @return void
+ * @private
+ */
+function includeFile($file)
+{
+    include $file;
 }

+ 5 - 12
vendor/composer/InstalledVersions.php

@@ -98,7 +98,7 @@ class InstalledVersions
     {
         foreach (self::getInstalled() as $installed) {
             if (isset($installed['versions'][$packageName])) {
-                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
+                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
             }
         }
 
@@ -119,7 +119,7 @@ class InstalledVersions
      */
     public static function satisfies(VersionParser $parser, $packageName, $constraint)
     {
-        $constraint = $parser->parseConstraints((string) $constraint);
+        $constraint = $parser->parseConstraints($constraint);
         $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
 
         return $provided->matches($constraint);
@@ -328,9 +328,7 @@ class InstalledVersions
                 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;
+                    $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
                     if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
                         self::$installed = $installed[count($installed) - 1];
                     }
@@ -342,17 +340,12 @@ class InstalledVersions
             // only require the installed.php file if this file is loaded from its dumped location,
             // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
             if (substr(__DIR__, -8, 1) !== 'C') {
-                /** @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 __DIR__ . '/installed.php';
-                self::$installed = $required;
+                self::$installed = require __DIR__ . '/installed.php';
             } else {
                 self::$installed = array();
             }
         }
-
-        if (self::$installed !== array()) {
-            $installed[] = self::$installed;
-        }
+        $installed[] = self::$installed;
 
         return $installed;
     }

+ 3 - 2
vendor/composer/autoload_psr4.php

@@ -6,10 +6,11 @@ $vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
+    'think\\mongo\\' => array($vendorDir . '/topthink/think-mongo/src'),
     'think\\helper\\' => array($vendorDir . '/topthink/think-helper/src'),
     'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'),
     'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'),
-    'think\\' => array($baseDir . '/thinkphp/library/think', $vendorDir . '/karsonzhang/fastadmin-addons/src', $vendorDir . '/topthink/think-queue/src'),
+    'think\\' => array($vendorDir . '/karsonzhang/fastadmin-addons/src', $baseDir . '/thinkphp/library/think', $vendorDir . '/topthink/think-queue/src'),
     'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
     'Tx\\' => array($vendorDir . '/txthinking/mailer/src'),
     'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
@@ -26,7 +27,7 @@ return array(
     'Symfony\\Bridge\\PsrHttpMessage\\' => array($vendorDir . '/symfony/psr-http-message-bridge'),
     'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
-    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
+    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
     'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
     'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'),
     'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),

+ 17 - 10
vendor/composer/autoload_real.php

@@ -33,18 +33,25 @@ class ComposerAutoloaderInita171a4a837511915e525c40585d599c6
 
         $loader->register(true);
 
-        $filesToLoad = \Composer\Autoload\ComposerStaticInita171a4a837511915e525c40585d599c6::$files;
-        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
-            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
-                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
-
-                require $file;
-            }
-        }, null, null);
-        foreach ($filesToLoad as $fileIdentifier => $file) {
-            $requireFile($fileIdentifier, $file);
+        $includeFiles = \Composer\Autoload\ComposerStaticInita171a4a837511915e525c40585d599c6::$files;
+        foreach ($includeFiles as $fileIdentifier => $file) {
+            composerRequirea171a4a837511915e525c40585d599c6($fileIdentifier, $file);
         }
 
         return $loader;
     }
 }
+
+/**
+ * @param string $fileIdentifier
+ * @param string $file
+ * @return void
+ */
+function composerRequirea171a4a837511915e525c40585d599c6($fileIdentifier, $file)
+{
+    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+
+        require $file;
+    }
+}

+ 9 - 4
vendor/composer/autoload_static.php

@@ -25,6 +25,7 @@ class ComposerStaticInita171a4a837511915e525c40585d599c6
     public static $prefixLengthsPsr4 = array (
         't' => 
         array (
+            'think\\mongo\\' => 12,
             'think\\helper\\' => 13,
             'think\\composer\\' => 15,
             'think\\captcha\\' => 14,
@@ -94,6 +95,10 @@ class ComposerStaticInita171a4a837511915e525c40585d599c6
     );
 
     public static $prefixDirsPsr4 = array (
+        'think\\mongo\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/topthink/think-mongo/src',
+        ),
         'think\\helper\\' => 
         array (
             0 => __DIR__ . '/..' . '/topthink/think-helper/src',
@@ -108,8 +113,8 @@ class ComposerStaticInita171a4a837511915e525c40585d599c6
         ),
         'think\\' => 
         array (
-            0 => __DIR__ . '/../..' . '/thinkphp/library/think',
-            1 => __DIR__ . '/..' . '/karsonzhang/fastadmin-addons/src',
+            0 => __DIR__ . '/..' . '/karsonzhang/fastadmin-addons/src',
+            1 => __DIR__ . '/../..' . '/thinkphp/library/think',
             2 => __DIR__ . '/..' . '/topthink/think-queue/src',
         ),
         'ZipStream\\' => 
@@ -178,8 +183,8 @@ class ComposerStaticInita171a4a837511915e525c40585d599c6
         ),
         'Psr\\Http\\Message\\' => 
         array (
-            0 => __DIR__ . '/..' . '/psr/http-message/src',
-            1 => __DIR__ . '/..' . '/psr/http-factory/src',
+            0 => __DIR__ . '/..' . '/psr/http-factory/src',
+            1 => __DIR__ . '/..' . '/psr/http-message/src',
         ),
         'Psr\\Http\\Client\\' => 
         array (

+ 220 - 186
vendor/composer/installed.json

@@ -53,21 +53,21 @@
         },
         {
             "name": "ezyang/htmlpurifier",
-            "version": "v4.16.0",
-            "version_normalized": "4.16.0.0",
+            "version": "v4.18.0",
+            "version_normalized": "4.18.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ezyang/htmlpurifier.git",
-                "reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8"
+                "reference": "cb56001e54359df7ae76dc522d08845dc741621b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/523407fb06eb9e5f3d59889b3978d5bfe94299c8",
-                "reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8",
+                "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b",
+                "reference": "cb56001e54359df7ae76dc522d08845dc741621b",
                 "shasum": ""
             },
             "require": {
-                "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0"
+                "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
             },
             "require-dev": {
                 "cerdic/css-tidy": "^1.7 || ^2.0",
@@ -79,7 +79,7 @@
                 "ext-iconv": "Converts text to and from non-UTF-8 encodings",
                 "ext-tidy": "Used for pretty-printing HTML"
             },
-            "time": "2022-09-18T07:06:19+00:00",
+            "time": "2024-11-01T03:51:45+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
@@ -111,29 +111,29 @@
             ],
             "support": {
                 "issues": "https://github.com/ezyang/htmlpurifier/issues",
-                "source": "https://github.com/ezyang/htmlpurifier/tree/v4.16.0"
+                "source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0"
             },
             "install-path": "../ezyang/htmlpurifier"
         },
         {
             "name": "guzzlehttp/guzzle",
-            "version": "7.7.0",
-            "version_normalized": "7.7.0.0",
+            "version": "7.9.3",
+            "version_normalized": "7.9.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5"
+                "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fb7566caccf22d74d1ab270de3551f72a58399f5",
-                "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
+                "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
-                "guzzlehttp/promises": "^1.5.3 || ^2.0",
-                "guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
+                "guzzlehttp/promises": "^1.5.3 || ^2.0.3",
+                "guzzlehttp/psr7": "^2.7.0",
                 "php": "^7.2.5 || ^8.0",
                 "psr/http-client": "^1.0",
                 "symfony/deprecation-contracts": "^2.2 || ^3.0"
@@ -142,11 +142,11 @@
                 "psr/http-client-implementation": "1.0"
             },
             "require-dev": {
-                "bamarni/composer-bin-plugin": "^1.8.1",
+                "bamarni/composer-bin-plugin": "^1.8.2",
                 "ext-curl": "*",
-                "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
+                "guzzle/client-integration-tests": "3.0.2",
                 "php-http/message-factory": "^1.1",
-                "phpunit/phpunit": "^8.5.29 || ^9.5.23",
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20",
                 "psr/log": "^1.1 || ^2.0 || ^3.0"
             },
             "suggest": {
@@ -154,7 +154,7 @@
                 "ext-intl": "Required for Internationalized Domain Name (IDN) support",
                 "psr/log": "Required for using the Log middleware"
             },
-            "time": "2023-05-21T14:04:53+00:00",
+            "time": "2025-03-27T13:37:11+00:00",
             "type": "library",
             "extra": {
                 "bamarni-bin": {
@@ -226,7 +226,7 @@
             ],
             "support": {
                 "issues": "https://github.com/guzzle/guzzle/issues",
-                "source": "https://github.com/guzzle/guzzle/tree/7.7.0"
+                "source": "https://github.com/guzzle/guzzle/tree/7.9.3"
             },
             "funding": [
                 {
@@ -246,27 +246,27 @@
         },
         {
             "name": "guzzlehttp/promises",
-            "version": "2.0.0",
-            "version_normalized": "2.0.0.0",
+            "version": "2.2.0",
+            "version_normalized": "2.2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/promises.git",
-                "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6"
+                "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/promises/zipball/3a494dc7dc1d7d12e511890177ae2d0e6c107da6",
-                "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
+                "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
                 "shasum": ""
             },
             "require": {
                 "php": "^7.2.5 || ^8.0"
             },
             "require-dev": {
-                "bamarni/composer-bin-plugin": "^1.8.1",
-                "phpunit/phpunit": "^8.5.29 || ^9.5.23"
+                "bamarni/composer-bin-plugin": "^1.8.2",
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20"
             },
-            "time": "2023-05-21T13:50:22+00:00",
+            "time": "2025-03-27T13:27:01+00:00",
             "type": "library",
             "extra": {
                 "bamarni-bin": {
@@ -312,7 +312,7 @@
             ],
             "support": {
                 "issues": "https://github.com/guzzle/promises/issues",
-                "source": "https://github.com/guzzle/promises/tree/2.0.0"
+                "source": "https://github.com/guzzle/promises/tree/2.2.0"
             },
             "funding": [
                 {
@@ -332,17 +332,17 @@
         },
         {
             "name": "guzzlehttp/psr7",
-            "version": "2.5.0",
-            "version_normalized": "2.5.0.0",
+            "version": "2.7.1",
+            "version_normalized": "2.7.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/psr7.git",
-                "reference": "b635f279edd83fc275f822a1188157ffea568ff6"
+                "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6",
-                "reference": "b635f279edd83fc275f822a1188157ffea568ff6",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
+                "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
                 "shasum": ""
             },
             "require": {
@@ -356,14 +356,14 @@
                 "psr/http-message-implementation": "1.0"
             },
             "require-dev": {
-                "bamarni/composer-bin-plugin": "^1.8.1",
-                "http-interop/http-factory-tests": "^0.9",
-                "phpunit/phpunit": "^8.5.29 || ^9.5.23"
+                "bamarni/composer-bin-plugin": "^1.8.2",
+                "http-interop/http-factory-tests": "0.9.0",
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20"
             },
             "suggest": {
                 "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
             },
-            "time": "2023-04-17T16:11:26+00:00",
+            "time": "2025-03-27T12:30:47+00:00",
             "type": "library",
             "extra": {
                 "bamarni-bin": {
@@ -431,7 +431,7 @@
             ],
             "support": {
                 "issues": "https://github.com/guzzle/psr7/issues",
-                "source": "https://github.com/guzzle/psr7/tree/2.5.0"
+                "source": "https://github.com/guzzle/psr7/tree/2.7.1"
             },
             "funding": [
                 {
@@ -703,17 +703,17 @@
         },
         {
             "name": "monolog/monolog",
-            "version": "2.9.1",
-            "version_normalized": "2.9.1.0",
+            "version": "2.10.0",
+            "version_normalized": "2.10.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Seldaek/monolog.git",
-                "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1"
+                "reference": "5cf826f2991858b54d5c3809bee745560a1042a7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
-                "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/5cf826f2991858b54d5c3809bee745560a1042a7",
+                "reference": "5cf826f2991858b54d5c3809bee745560a1042a7",
                 "shasum": ""
             },
             "require": {
@@ -734,8 +734,8 @@
                 "mongodb/mongodb": "^1.8",
                 "php-amqplib/php-amqplib": "~2.4 || ^3",
                 "phpspec/prophecy": "^1.15",
-                "phpstan/phpstan": "^0.12.91",
-                "phpunit/phpunit": "^8.5.14",
+                "phpstan/phpstan": "^1.10",
+                "phpunit/phpunit": "^8.5.38 || ^9.6.19",
                 "predis/predis": "^1.1 || ^2.0",
                 "rollbar/rollbar": "^1.3 || ^2 || ^3",
                 "ruflin/elastica": "^7",
@@ -759,7 +759,7 @@
                 "rollbar/rollbar": "Allow sending log messages to Rollbar",
                 "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
             },
-            "time": "2023-02-06T13:44:46+00:00",
+            "time": "2024-11-12T12:43:37+00:00",
             "type": "library",
             "extra": {
                 "branch-alias": {
@@ -792,7 +792,7 @@
             ],
             "support": {
                 "issues": "https://github.com/Seldaek/monolog/issues",
-                "source": "https://github.com/Seldaek/monolog/tree/2.9.1"
+                "source": "https://github.com/Seldaek/monolog/tree/2.10.0"
             },
             "funding": [
                 {
@@ -808,17 +808,17 @@
         },
         {
             "name": "myclabs/php-enum",
-            "version": "1.8.4",
-            "version_normalized": "1.8.4.0",
+            "version": "1.8.5",
+            "version_normalized": "1.8.5.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/myclabs/php-enum.git",
-                "reference": "a867478eae49c9f59ece437ae7f9506bfaa27483"
+                "reference": "e7be26966b7398204a234f8673fdad5ac6277802"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/myclabs/php-enum/zipball/a867478eae49c9f59ece437ae7f9506bfaa27483",
-                "reference": "a867478eae49c9f59ece437ae7f9506bfaa27483",
+                "url": "https://api.github.com/repos/myclabs/php-enum/zipball/e7be26966b7398204a234f8673fdad5ac6277802",
+                "reference": "e7be26966b7398204a234f8673fdad5ac6277802",
                 "shasum": ""
             },
             "require": {
@@ -828,9 +828,9 @@
             "require-dev": {
                 "phpunit/phpunit": "^9.5",
                 "squizlabs/php_codesniffer": "1.*",
-                "vimeo/psalm": "^4.6.2"
+                "vimeo/psalm": "^4.6.2 || ^5.2"
             },
-            "time": "2022-08-04T09:53:51+00:00",
+            "time": "2025-01-14T11:49:03+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
@@ -852,13 +852,13 @@
                 }
             ],
             "description": "PHP Enum implementation",
-            "homepage": "http://github.com/myclabs/php-enum",
+            "homepage": "https://github.com/myclabs/php-enum",
             "keywords": [
                 "enum"
             ],
             "support": {
                 "issues": "https://github.com/myclabs/php-enum/issues",
-                "source": "https://github.com/myclabs/php-enum/tree/1.8.4"
+                "source": "https://github.com/myclabs/php-enum/tree/1.8.5"
             },
             "funding": [
                 {
@@ -1521,24 +1521,24 @@
         },
         {
             "name": "psr/http-client",
-            "version": "1.0.2",
-            "version_normalized": "1.0.2.0",
+            "version": "1.0.3",
+            "version_normalized": "1.0.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/http-client.git",
-                "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31"
+                "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31",
-                "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31",
+                "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
+                "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
                 "shasum": ""
             },
             "require": {
                 "php": "^7.0 || ^8.0",
                 "psr/http-message": "^1.0 || ^2.0"
             },
-            "time": "2023-04-10T20:12:12+00:00",
+            "time": "2023-09-23T14:17:50+00:00",
             "type": "library",
             "extra": {
                 "branch-alias": {
@@ -1570,30 +1570,30 @@
                 "psr-18"
             ],
             "support": {
-                "source": "https://github.com/php-fig/http-client/tree/1.0.2"
+                "source": "https://github.com/php-fig/http-client"
             },
             "install-path": "../psr/http-client"
         },
         {
             "name": "psr/http-factory",
-            "version": "1.0.2",
-            "version_normalized": "1.0.2.0",
+            "version": "1.1.0",
+            "version_normalized": "1.1.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/http-factory.git",
-                "reference": "e616d01114759c4c489f93b099585439f795fe35"
+                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
-                "reference": "e616d01114759c4c489f93b099585439f795fe35",
+                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
+                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.0.0",
+                "php": ">=7.1",
                 "psr/http-message": "^1.0 || ^2.0"
             },
-            "time": "2023-04-10T20:10:41+00:00",
+            "time": "2024-04-15T12:06:14+00:00",
             "type": "library",
             "extra": {
                 "branch-alias": {
@@ -1616,7 +1616,7 @@
                     "homepage": "https://www.php-fig.org/"
                 }
             ],
-            "description": "Common interfaces for PSR-7 HTTP message factories",
+            "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
             "keywords": [
                 "factory",
                 "http",
@@ -1628,7 +1628,7 @@
                 "response"
             ],
             "support": {
-                "source": "https://github.com/php-fig/http-factory/tree/1.0.2"
+                "source": "https://github.com/php-fig/http-factory"
             },
             "install-path": "../psr/http-factory"
         },
@@ -1844,17 +1844,17 @@
         },
         {
             "name": "symfony/cache",
-            "version": "v5.4.25",
-            "version_normalized": "5.4.25.0",
+            "version": "v5.4.46",
+            "version_normalized": "5.4.46.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/cache.git",
-                "reference": "e2013521c0f07473ae69a01fce0af78fc3ec0f23"
+                "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/cache/zipball/e2013521c0f07473ae69a01fce0af78fc3ec0f23",
-                "reference": "e2013521c0f07473ae69a01fce0af78fc3ec0f23",
+                "url": "https://api.github.com/repos/symfony/cache/zipball/0fe08ee32cec2748fbfea10c52d3ee02049e0f6b",
+                "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b",
                 "shasum": ""
             },
             "require": {
@@ -1882,8 +1882,8 @@
             "require-dev": {
                 "cache/integration-tests": "dev-master",
                 "doctrine/cache": "^1.6|^2.0",
-                "doctrine/dbal": "^2.13.1|^3.0",
-                "predis/predis": "^1.1",
+                "doctrine/dbal": "^2.13.1|^3|^4",
+                "predis/predis": "^1.1|^2.0",
                 "psr/simple-cache": "^1.0|^2.0",
                 "symfony/config": "^4.4|^5.0|^6.0",
                 "symfony/dependency-injection": "^4.4|^5.0|^6.0",
@@ -1892,7 +1892,7 @@
                 "symfony/messenger": "^4.4|^5.0|^6.0",
                 "symfony/var-dumper": "^4.4|^5.0|^6.0"
             },
-            "time": "2023-06-22T08:06:06+00:00",
+            "time": "2024-11-04T11:43:55+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
@@ -1924,7 +1924,7 @@
                 "psr6"
             ],
             "support": {
-                "source": "https://github.com/symfony/cache/tree/v5.4.25"
+                "source": "https://github.com/symfony/cache/tree/v5.4.46"
             },
             "funding": [
                 {
@@ -1944,17 +1944,17 @@
         },
         {
             "name": "symfony/cache-contracts",
-            "version": "v2.5.2",
-            "version_normalized": "2.5.2.0",
+            "version": "v2.5.4",
+            "version_normalized": "2.5.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/cache-contracts.git",
-                "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc"
+                "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
-                "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
+                "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/517c3a3619dadfa6952c4651767fcadffb4df65e",
+                "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e",
                 "shasum": ""
             },
             "require": {
@@ -1964,15 +1964,15 @@
             "suggest": {
                 "symfony/cache-implementation": ""
             },
-            "time": "2022-01-02T09:53:40+00:00",
+            "time": "2024-09-25T14:11:13+00:00",
             "type": "library",
             "extra": {
+                "thanks": {
+                    "url": "https://github.com/symfony/contracts",
+                    "name": "symfony/contracts"
+                },
                 "branch-alias": {
                     "dev-main": "2.5-dev"
-                },
-                "thanks": {
-                    "name": "symfony/contracts",
-                    "url": "https://github.com/symfony/contracts"
                 }
             },
             "installation-source": "dist",
@@ -2006,7 +2006,7 @@
                 "standards"
             ],
             "support": {
-                "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2"
+                "source": "https://github.com/symfony/cache-contracts/tree/v2.5.4"
             },
             "funding": [
                 {
@@ -2026,31 +2026,31 @@
         },
         {
             "name": "symfony/deprecation-contracts",
-            "version": "v2.5.2",
-            "version_normalized": "2.5.2.0",
+            "version": "v2.5.4",
+            "version_normalized": "2.5.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/deprecation-contracts.git",
-                "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
+                "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
-                "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
+                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918",
+                "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.1"
             },
-            "time": "2022-01-02T09:53:40+00:00",
+            "time": "2024-09-25T14:11:13+00:00",
             "type": "library",
             "extra": {
+                "thanks": {
+                    "url": "https://github.com/symfony/contracts",
+                    "name": "symfony/contracts"
+                },
                 "branch-alias": {
                     "dev-main": "2.5-dev"
-                },
-                "thanks": {
-                    "name": "symfony/contracts",
-                    "url": "https://github.com/symfony/contracts"
                 }
             },
             "installation-source": "dist",
@@ -2076,7 +2076,7 @@
             "description": "A generic function and convention to trigger deprecation notices",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
+                "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4"
             },
             "funding": [
                 {
@@ -2096,17 +2096,17 @@
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v5.4.22",
-            "version_normalized": "5.4.22.0",
+            "version": "v5.4.45",
+            "version_normalized": "5.4.45.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f"
+                "reference": "72982eb416f61003e9bb6e91f8b3213600dcf9e9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1df20e45d56da29a4b1d8259dd6e950acbf1b13f",
-                "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/72982eb416f61003e9bb6e91f8b3213600dcf9e9",
+                "reference": "72982eb416f61003e9bb6e91f8b3213600dcf9e9",
                 "shasum": ""
             },
             "require": {
@@ -2136,7 +2136,7 @@
                 "symfony/dependency-injection": "",
                 "symfony/http-kernel": ""
             },
-            "time": "2023-03-17T11:31:58+00:00",
+            "time": "2024-09-25T14:11:13+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
@@ -2164,7 +2164,7 @@
             "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.22"
+                "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.45"
             },
             "funding": [
                 {
@@ -2184,17 +2184,17 @@
         },
         {
             "name": "symfony/event-dispatcher-contracts",
-            "version": "v2.5.2",
-            "version_normalized": "2.5.2.0",
+            "version": "v2.5.4",
+            "version_normalized": "2.5.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher-contracts.git",
-                "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1"
+                "reference": "e0fe3d79b516eb75126ac6fa4cbf19b79b08c99f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1",
-                "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/e0fe3d79b516eb75126ac6fa4cbf19b79b08c99f",
+                "reference": "e0fe3d79b516eb75126ac6fa4cbf19b79b08c99f",
                 "shasum": ""
             },
             "require": {
@@ -2204,15 +2204,15 @@
             "suggest": {
                 "symfony/event-dispatcher-implementation": ""
             },
-            "time": "2022-01-02T09:53:40+00:00",
+            "time": "2024-09-25T14:11:13+00:00",
             "type": "library",
             "extra": {
+                "thanks": {
+                    "url": "https://github.com/symfony/contracts",
+                    "name": "symfony/contracts"
+                },
                 "branch-alias": {
                     "dev-main": "2.5-dev"
-                },
-                "thanks": {
-                    "name": "symfony/contracts",
-                    "url": "https://github.com/symfony/contracts"
                 }
             },
             "installation-source": "dist",
@@ -2246,7 +2246,7 @@
                 "standards"
             ],
             "support": {
-                "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2"
+                "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.4"
             },
             "funding": [
                 {
@@ -2266,17 +2266,17 @@
         },
         {
             "name": "symfony/finder",
-            "version": "v5.4.21",
-            "version_normalized": "5.4.21.0",
+            "version": "v5.4.45",
+            "version_normalized": "5.4.45.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19"
+                "reference": "63741784cd7b9967975eec610b256eed3ede022b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19",
-                "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/63741784cd7b9967975eec610b256eed3ede022b",
+                "reference": "63741784cd7b9967975eec610b256eed3ede022b",
                 "shasum": ""
             },
             "require": {
@@ -2284,7 +2284,7 @@
                 "symfony/deprecation-contracts": "^2.1|^3",
                 "symfony/polyfill-php80": "^1.16"
             },
-            "time": "2023-02-16T09:33:00+00:00",
+            "time": "2024-09-28T13:32:08+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
@@ -2312,7 +2312,7 @@
             "description": "Finds files and directories via an intuitive fluent interface",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/finder/tree/v5.4.21"
+                "source": "https://github.com/symfony/finder/tree/v5.4.45"
             },
             "funding": [
                 {
@@ -2332,17 +2332,17 @@
         },
         {
             "name": "symfony/http-foundation",
-            "version": "v5.4.25",
-            "version_normalized": "5.4.25.0",
+            "version": "v5.4.48",
+            "version_normalized": "5.4.48.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "f66be2706075c5f6325d2fe2b743a57fb5d23f6b"
+                "reference": "3f38b8af283b830e1363acd79e5bc3412d055341"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f66be2706075c5f6325d2fe2b743a57fb5d23f6b",
-                "reference": "f66be2706075c5f6325d2fe2b743a57fb5d23f6b",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3f38b8af283b830e1363acd79e5bc3412d055341",
+                "reference": "3f38b8af283b830e1363acd79e5bc3412d055341",
                 "shasum": ""
             },
             "require": {
@@ -2352,7 +2352,7 @@
                 "symfony/polyfill-php80": "^1.16"
             },
             "require-dev": {
-                "predis/predis": "~1.0",
+                "predis/predis": "^1.0|^2.0",
                 "symfony/cache": "^4.4|^5.0|^6.0",
                 "symfony/dependency-injection": "^5.4|^6.0",
                 "symfony/expression-language": "^4.4|^5.0|^6.0",
@@ -2363,7 +2363,7 @@
             "suggest": {
                 "symfony/mime": "To use the file extension guesser"
             },
-            "time": "2023-06-22T08:06:06+00:00",
+            "time": "2024-11-13T18:58:02+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
@@ -2391,7 +2391,7 @@
             "description": "Defines an object-oriented layer for the HTTP specification",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/http-foundation/tree/v5.4.25"
+                "source": "https://github.com/symfony/http-foundation/tree/v5.4.48"
             },
             "funding": [
                 {
@@ -2411,21 +2411,22 @@
         },
         {
             "name": "symfony/polyfill-mbstring",
-            "version": "v1.27.0",
-            "version_normalized": "1.27.0.0",
+            "version": "v1.32.0",
+            "version_normalized": "1.32.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
+                "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
-                "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+                "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "ext-iconv": "*",
+                "php": ">=7.2"
             },
             "provide": {
                 "ext-mbstring": "*"
@@ -2433,15 +2434,12 @@
             "suggest": {
                 "ext-mbstring": "For best performance"
             },
-            "time": "2022-11-03T14:55:06+00:00",
+            "time": "2024-12-23T08:48:59+00:00",
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "1.27-dev"
-                },
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "installation-source": "dist",
@@ -2477,7 +2475,7 @@
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
+                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
             },
             "funding": [
                 {
@@ -2497,31 +2495,28 @@
         },
         {
             "name": "symfony/polyfill-php73",
-            "version": "v1.27.0",
-            "version_normalized": "1.27.0.0",
+            "version": "v1.32.0",
+            "version_normalized": "1.32.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php73.git",
-                "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9"
+                "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
-                "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
+                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
+                "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "php": ">=7.2"
             },
-            "time": "2022-11-03T14:55:06+00:00",
+            "time": "2024-09-09T11:45:10+00:00",
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "1.27-dev"
-                },
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "installation-source": "dist",
@@ -2559,7 +2554,7 @@
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0"
+                "source": "https://github.com/symfony/polyfill-php73/tree/v1.32.0"
             },
             "funding": [
                 {
@@ -2579,31 +2574,28 @@
         },
         {
             "name": "symfony/polyfill-php80",
-            "version": "v1.27.0",
-            "version_normalized": "1.27.0.0",
+            "version": "v1.32.0",
+            "version_normalized": "1.32.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php80.git",
-                "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
+                "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
-                "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+                "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "php": ">=7.2"
             },
-            "time": "2022-11-03T14:55:06+00:00",
+            "time": "2025-01-02T08:10:11+00:00",
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "1.27-dev"
-                },
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "installation-source": "dist",
@@ -2645,7 +2637,7 @@
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
+                "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
             },
             "funding": [
                 {
@@ -2665,22 +2657,23 @@
         },
         {
             "name": "symfony/psr-http-message-bridge",
-            "version": "v2.2.0",
-            "version_normalized": "2.2.0.0",
+            "version": "v2.3.1",
+            "version_normalized": "2.3.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/psr-http-message-bridge.git",
-                "reference": "28a732c05bbad801304ad5a5c674cf2970508993"
+                "reference": "581ca6067eb62640de5ff08ee1ba6850a0ee472e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/28a732c05bbad801304ad5a5c674cf2970508993",
-                "reference": "28a732c05bbad801304ad5a5c674cf2970508993",
+                "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/581ca6067eb62640de5ff08ee1ba6850a0ee472e",
+                "reference": "581ca6067eb62640de5ff08ee1ba6850a0ee472e",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.2.5",
                 "psr/http-message": "^1.0 || ^2.0",
+                "symfony/deprecation-contracts": "^2.5 || ^3.0",
                 "symfony/http-foundation": "^5.4 || ^6.0"
             },
             "require-dev": {
@@ -2696,11 +2689,11 @@
             "suggest": {
                 "nyholm/psr7": "For a super lightweight PSR-7/17 implementation"
             },
-            "time": "2023-04-21T08:40:19+00:00",
+            "time": "2023-07-26T11:53:26+00:00",
             "type": "symfony-bridge",
             "extra": {
                 "branch-alias": {
-                    "dev-main": "2.2-dev"
+                    "dev-main": "2.3-dev"
                 }
             },
             "installation-source": "dist",
@@ -2736,7 +2729,7 @@
             ],
             "support": {
                 "issues": "https://github.com/symfony/psr-http-message-bridge/issues",
-                "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.2.0"
+                "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.3.1"
             },
             "funding": [
                 {
@@ -2901,7 +2894,7 @@
             "source": {
                 "type": "git",
                 "url": "https://gitee.com/fastadminnet/framework.git",
-                "reference": "096811899433eb0eb0988f1fe1db56ebb521bf34"
+                "reference": "0216ba50273067594907178ea299c86ed6a39656"
             },
             "require": {
                 "php": ">=7.1.0",
@@ -2915,7 +2908,7 @@
                 "phpunit/phpunit": "4.8.*",
                 "sebastian/phpcpd": "2.*"
             },
-            "time": "2022-12-19T02:13:42+00:00",
+            "time": "2025-06-17T03:27:15+00:00",
             "default-branch": true,
             "type": "think-framework",
             "installation-source": "source",
@@ -3076,6 +3069,47 @@
             },
             "install-path": "../topthink/think-installer"
         },
+        {
+            "name": "topthink/think-mongo",
+            "version": "1.0",
+            "version_normalized": "1.0.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/think-mongo.git",
+                "reference": "74bddade9022da835c72bcb1e02c4bf8527f6dc2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/think-mongo/zipball/74bddade9022da835c72bcb1e02c4bf8527f6dc2",
+                "reference": "74bddade9022da835c72bcb1e02c4bf8527f6dc2",
+                "shasum": ""
+            },
+            "time": "2016-09-13T13:25:52+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "files": [],
+                "psr-4": {
+                    "think\\mongo\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "liu21st",
+                    "email": "liu21st@gmail.com"
+                }
+            ],
+            "description": "mongodb driver for thinkphp5",
+            "support": {
+                "issues": "https://github.com/top-think/think-mongo/issues",
+                "source": "https://github.com/top-think/think-mongo/tree/master"
+            },
+            "install-path": "../topthink/think-mongo"
+        },
         {
             "name": "topthink/think-queue",
             "version": "v1.1.6",

+ 73 - 64
vendor/composer/installed.php

@@ -1,9 +1,9 @@
 <?php return array(
     'root' => array(
         'name' => 'karsonzhang/fastadmin',
-        'pretty_version' => '1.x-dev',
-        'version' => '1.9999999.9999999.9999999-dev',
-        'reference' => '033af96e1a05ef67ae55ba8d2870b54fffb17fcf',
+        'pretty_version' => 'dev-master',
+        'version' => 'dev-master',
+        'reference' => '90d7ac2c0582d2c9709c77a904d16bc31078f13e',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -20,45 +20,45 @@
             'dev_requirement' => false,
         ),
         'ezyang/htmlpurifier' => array(
-            'pretty_version' => 'v4.16.0',
-            'version' => '4.16.0.0',
-            'reference' => '523407fb06eb9e5f3d59889b3978d5bfe94299c8',
+            'pretty_version' => 'v4.18.0',
+            'version' => '4.18.0.0',
+            'reference' => 'cb56001e54359df7ae76dc522d08845dc741621b',
             'type' => 'library',
             'install_path' => __DIR__ . '/../ezyang/htmlpurifier',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'guzzlehttp/guzzle' => array(
-            'pretty_version' => '7.7.0',
-            'version' => '7.7.0.0',
-            'reference' => 'fb7566caccf22d74d1ab270de3551f72a58399f5',
+            '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.0',
-            'version' => '2.0.0.0',
-            'reference' => '3a494dc7dc1d7d12e511890177ae2d0e6c107da6',
+            '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.5.0',
-            'version' => '2.5.0.0',
-            'reference' => 'b635f279edd83fc275f822a1188157ffea568ff6',
+            'pretty_version' => '2.7.1',
+            'version' => '2.7.1.0',
+            'reference' => 'c2270caaabe631b3b44c85f99e5a04bbb8060d16',
             'type' => 'library',
             'install_path' => __DIR__ . '/../guzzlehttp/psr7',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'karsonzhang/fastadmin' => array(
-            'pretty_version' => '1.x-dev',
-            'version' => '1.9999999.9999999.9999999-dev',
-            'reference' => '033af96e1a05ef67ae55ba8d2870b54fffb17fcf',
+            'pretty_version' => 'dev-master',
+            'version' => 'dev-master',
+            'reference' => '90d7ac2c0582d2c9709c77a904d16bc31078f13e',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
@@ -101,18 +101,18 @@
             'dev_requirement' => false,
         ),
         'monolog/monolog' => array(
-            'pretty_version' => '2.9.1',
-            'version' => '2.9.1.0',
-            'reference' => 'f259e2b15fb95494c83f52d3caad003bbf5ffaa1',
+            'pretty_version' => '2.10.0',
+            'version' => '2.10.0.0',
+            'reference' => '5cf826f2991858b54d5c3809bee745560a1042a7',
             'type' => 'library',
             'install_path' => __DIR__ . '/../monolog/monolog',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'myclabs/php-enum' => array(
-            'pretty_version' => '1.8.4',
-            'version' => '1.8.4.0',
-            'reference' => 'a867478eae49c9f59ece437ae7f9506bfaa27483',
+            'pretty_version' => '1.8.5',
+            'version' => '1.8.5.0',
+            'reference' => 'e7be26966b7398204a234f8673fdad5ac6277802',
             'type' => 'library',
             'install_path' => __DIR__ . '/../myclabs/php-enum',
             'aliases' => array(),
@@ -221,9 +221,9 @@
             ),
         ),
         'psr/http-client' => array(
-            'pretty_version' => '1.0.2',
-            'version' => '1.0.2.0',
-            'reference' => '0955afe48220520692d2d09f7ab7e0f93ffd6a31',
+            'pretty_version' => '1.0.3',
+            'version' => '1.0.3.0',
+            'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
             'type' => 'library',
             'install_path' => __DIR__ . '/../psr/http-client',
             'aliases' => array(),
@@ -236,9 +236,9 @@
             ),
         ),
         'psr/http-factory' => array(
-            'pretty_version' => '1.0.2',
-            'version' => '1.0.2.0',
-            'reference' => 'e616d01114759c4c489f93b099585439f795fe35',
+            'pretty_version' => '1.1.0',
+            'version' => '1.1.0.0',
+            'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
             'type' => 'library',
             'install_path' => __DIR__ . '/../psr/http-factory',
             'aliases' => array(),
@@ -305,18 +305,18 @@
             'dev_requirement' => false,
         ),
         'symfony/cache' => array(
-            'pretty_version' => 'v5.4.25',
-            'version' => '5.4.25.0',
-            'reference' => 'e2013521c0f07473ae69a01fce0af78fc3ec0f23',
+            'pretty_version' => 'v5.4.46',
+            'version' => '5.4.46.0',
+            'reference' => '0fe08ee32cec2748fbfea10c52d3ee02049e0f6b',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/cache',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'symfony/cache-contracts' => array(
-            'pretty_version' => 'v2.5.2',
-            'version' => '2.5.2.0',
-            'reference' => '64be4a7acb83b6f2bf6de9a02cee6dad41277ebc',
+            'pretty_version' => 'v2.5.4',
+            'version' => '2.5.4.0',
+            'reference' => '517c3a3619dadfa6952c4651767fcadffb4df65e',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/cache-contracts',
             'aliases' => array(),
@@ -329,27 +329,27 @@
             ),
         ),
         'symfony/deprecation-contracts' => array(
-            'pretty_version' => 'v2.5.2',
-            'version' => '2.5.2.0',
-            'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66',
+            'pretty_version' => 'v2.5.4',
+            'version' => '2.5.4.0',
+            'reference' => '605389f2a7e5625f273b53960dc46aeaf9c62918',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'symfony/event-dispatcher' => array(
-            'pretty_version' => 'v5.4.22',
-            'version' => '5.4.22.0',
-            'reference' => '1df20e45d56da29a4b1d8259dd6e950acbf1b13f',
+            'pretty_version' => 'v5.4.45',
+            'version' => '5.4.45.0',
+            'reference' => '72982eb416f61003e9bb6e91f8b3213600dcf9e9',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/event-dispatcher',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'symfony/event-dispatcher-contracts' => array(
-            'pretty_version' => 'v2.5.2',
-            'version' => '2.5.2.0',
-            'reference' => 'f98b54df6ad059855739db6fcbc2d36995283fe1',
+            'pretty_version' => 'v2.5.4',
+            'version' => '2.5.4.0',
+            'reference' => 'e0fe3d79b516eb75126ac6fa4cbf19b79b08c99f',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts',
             'aliases' => array(),
@@ -362,54 +362,54 @@
             ),
         ),
         'symfony/finder' => array(
-            'pretty_version' => 'v5.4.21',
-            'version' => '5.4.21.0',
-            'reference' => '078e9a5e1871fcfe6a5ce421b539344c21afef19',
+            'pretty_version' => 'v5.4.45',
+            'version' => '5.4.45.0',
+            'reference' => '63741784cd7b9967975eec610b256eed3ede022b',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/finder',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'symfony/http-foundation' => array(
-            'pretty_version' => 'v5.4.25',
-            'version' => '5.4.25.0',
-            'reference' => 'f66be2706075c5f6325d2fe2b743a57fb5d23f6b',
+            'pretty_version' => 'v5.4.48',
+            'version' => '5.4.48.0',
+            'reference' => '3f38b8af283b830e1363acd79e5bc3412d055341',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/http-foundation',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'symfony/polyfill-mbstring' => array(
-            'pretty_version' => 'v1.27.0',
-            'version' => '1.27.0.0',
-            'reference' => '8ad114f6b39e2c98a8b0e3bd907732c207c2b534',
+            'pretty_version' => 'v1.32.0',
+            'version' => '1.32.0.0',
+            'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'symfony/polyfill-php73' => array(
-            'pretty_version' => 'v1.27.0',
-            'version' => '1.27.0.0',
-            'reference' => '9e8ecb5f92152187c4799efd3c96b78ccab18ff9',
+            'pretty_version' => 'v1.32.0',
+            'version' => '1.32.0.0',
+            'reference' => '0f68c03565dcaaf25a890667542e8bd75fe7e5bb',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/polyfill-php73',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'symfony/polyfill-php80' => array(
-            'pretty_version' => 'v1.27.0',
-            'version' => '1.27.0.0',
-            'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936',
+            'pretty_version' => 'v1.32.0',
+            'version' => '1.32.0.0',
+            'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/polyfill-php80',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'symfony/psr-http-message-bridge' => array(
-            'pretty_version' => 'v2.2.0',
-            'version' => '2.2.0.0',
-            'reference' => '28a732c05bbad801304ad5a5c674cf2970508993',
+            'pretty_version' => 'v2.3.1',
+            'version' => '2.3.1.0',
+            'reference' => '581ca6067eb62640de5ff08ee1ba6850a0ee472e',
             'type' => 'symfony-bridge',
             'install_path' => __DIR__ . '/../symfony/psr-http-message-bridge',
             'aliases' => array(),
@@ -436,7 +436,7 @@
         'topthink/framework' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => '096811899433eb0eb0988f1fe1db56ebb521bf34',
+            'reference' => '0216ba50273067594907178ea299c86ed6a39656',
             'type' => 'think-framework',
             'install_path' => __DIR__ . '/../../thinkphp',
             'aliases' => array(
@@ -471,6 +471,15 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'topthink/think-mongo' => array(
+            'pretty_version' => '1.0',
+            'version' => '1.0.0.0',
+            'reference' => '74bddade9022da835c72bcb1e02c4bf8527f6dc2',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../topthink/think-mongo',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'topthink/think-queue' => array(
             'pretty_version' => 'v1.1.6',
             'version' => '1.1.6.0',

+ 0 - 6
vendor/ezyang/htmlpurifier/CHANGELOG.md

@@ -1,6 +0,0 @@
-# [4.16.0](https://github.com/ezyang/htmlpurifier/compare/v4.15.0...v4.16.0) (2022-09-18)
-
-
-### Features
-
-* add semantic release ([#307](https://github.com/ezyang/htmlpurifier/issues/307)) ([db31243](https://github.com/ezyang/htmlpurifier/commit/db312435cb9d8d73395f75f9642a43ba6de5e903)), closes [#322](https://github.com/ezyang/htmlpurifier/issues/322) [#323](https://github.com/ezyang/htmlpurifier/issues/323) [#326](https://github.com/ezyang/htmlpurifier/issues/326) [#327](https://github.com/ezyang/htmlpurifier/issues/327) [#328](https://github.com/ezyang/htmlpurifier/issues/328) [#329](https://github.com/ezyang/htmlpurifier/issues/329) [#330](https://github.com/ezyang/htmlpurifier/issues/330) [#331](https://github.com/ezyang/htmlpurifier/issues/331) [#332](https://github.com/ezyang/htmlpurifier/issues/332) [#333](https://github.com/ezyang/htmlpurifier/issues/333) [#337](https://github.com/ezyang/htmlpurifier/issues/337) [#335](https://github.com/ezyang/htmlpurifier/issues/335) [ezyang/htmlpurifier#334](https://github.com/ezyang/htmlpurifier/issues/334) [#336](https://github.com/ezyang/htmlpurifier/issues/336) [#338](https://github.com/ezyang/htmlpurifier/issues/338)

+ 1 - 1
vendor/ezyang/htmlpurifier/VERSION

@@ -1 +1 @@
-4.15.0
+4.18.0

+ 3 - 2
vendor/ezyang/htmlpurifier/composer.json

@@ -13,7 +13,7 @@
         }
     ],
     "require": {
-        "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0"
+        "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
     },
     "require-dev": {
         "cerdic/css-tidy": "^1.7 || ^2.0",
@@ -38,7 +38,8 @@
     "repositories": [
         {
             "type": "vcs",
-            "url": "https://github.com/ezyang/simpletest.git"
+            "url": "https://github.com/ezyang/simpletest.git",
+            "no-api": true
         }
     ]
 }

+ 2 - 1
vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php

@@ -7,7 +7,7 @@
  * primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
  * FILE, changes will be overwritten the next time the script is run.
  *
- * @version 4.15.0
+ * @version 4.18.0
  *
  * @warning
  *      You must *not* include any other HTML Purifier files before this file,
@@ -101,6 +101,7 @@ require 'HTMLPurifier/AttrDef/CSS/Length.php';
 require 'HTMLPurifier/AttrDef/CSS/ListStyle.php';
 require 'HTMLPurifier/AttrDef/CSS/Multiple.php';
 require 'HTMLPurifier/AttrDef/CSS/Percentage.php';
+require 'HTMLPurifier/AttrDef/CSS/Ratio.php';
 require 'HTMLPurifier/AttrDef/CSS/TextDecoration.php';
 require 'HTMLPurifier/AttrDef/CSS/URI.php';
 require 'HTMLPurifier/AttrDef/HTML/Bool.php';

+ 3 - 3
vendor/ezyang/htmlpurifier/library/HTMLPurifier.php

@@ -19,7 +19,7 @@
  */
 
 /*
-    HTML Purifier 4.15.0 - Standards Compliant HTML Filtering
+    HTML Purifier 4.18.0 - Standards Compliant HTML Filtering
     Copyright (C) 2006-2008 Edward Z. Yang
 
     This library is free software; you can redistribute it and/or
@@ -58,12 +58,12 @@ class HTMLPurifier
      * Version of HTML Purifier.
      * @type string
      */
-    public $version = '4.15.0';
+    public $version = '4.18.0';
 
     /**
      * Constant with version of HTML Purifier.
      */
-    const VERSION = '4.15.0';
+    const VERSION = '4.18.0';
 
     /**
      * Global configuration object.

+ 1 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php

@@ -95,6 +95,7 @@ require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Length.php';
 require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ListStyle.php';
 require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Multiple.php';
 require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Percentage.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Ratio.php';
 require_once $__dir . '/HTMLPurifier/AttrDef/CSS/TextDecoration.php';
 require_once $__dir . '/HTMLPurifier/AttrDef/CSS/URI.php';
 require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Bool.php';

+ 9 - 5
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php

@@ -27,6 +27,13 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
         $definition = $config->getCSSDefinition();
         $allow_duplicates = $config->get("CSS.AllowDuplicates");
 
+        $universal_attrdef = new HTMLPurifier_AttrDef_Enum(
+            array(
+                'initial',
+                'inherit',
+                'unset',
+            )
+        );
 
         // According to the CSS2.1 spec, the places where a
         // non-delimiting semicolon can appear are in strings
@@ -96,16 +103,13 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
             if (!$ok) {
                 continue;
             }
-            // inefficient call, since the validator will do this again
-            if (strtolower(trim($value)) !== 'inherit') {
-                // inherit works for everything (but only on the base property)
+            $result = $universal_attrdef->validate($value, $config, $context);
+            if ($result === false) {
                 $result = $definition->info[$property]->validate(
                     $value,
                     $config,
                     $context
                 );
-            } else {
-                $result = 'inherit';
             }
             if ($result === false) {
                 continue;

+ 15 - 17
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php

@@ -10,23 +10,21 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
 
     public function __construct()
     {
-        $this->mask = '_- ';
-        for ($c = 'a'; $c <= 'z'; $c++) {
-            $this->mask .= $c;
-        }
-        for ($c = 'A'; $c <= 'Z'; $c++) {
-            $this->mask .= $c;
-        }
-        for ($c = '0'; $c <= '9'; $c++) {
-            $this->mask .= $c;
-        } // cast-y, but should be fine
-        // special bytes used by UTF-8
-        for ($i = 0x80; $i <= 0xFF; $i++) {
-            // We don't bother excluding invalid bytes in this range,
-            // because the our restriction of well-formed UTF-8 will
-            // prevent these from ever occurring.
-            $this->mask .= chr($i);
-        }
+        // Lowercase letters
+        $l = range('a', 'z');
+        // Uppercase letters
+        $u = range('A', 'Z');
+        // Digits
+        $d = range('0', '9');
+        // Special bytes used by UTF-8
+        $b = array_map('chr', range(0x80, 0xFF));
+        // All valid characters for the mask
+        $c = array_merge($l, $u, $d, $b);
+        // Concatenate all valid characters into a string 
+        // Use '_- ' as an initial value
+        $this->mask = array_reduce($c, function ($carry, $value) {
+            return $carry . $value;
+        }, '_- ');
 
         /*
             PHP's internal strcspn implementation is

+ 46 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ratio.php

@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Validates a ratio as defined by the CSS spec.
+ */
+class HTMLPurifier_AttrDef_CSS_Ratio extends HTMLPurifier_AttrDef
+{
+    /**
+     * @param   string               $ratio   Ratio to validate
+     * @param   HTMLPurifier_Config  $config  Configuration options
+     * @param   HTMLPurifier_Context $context Context
+     *
+     * @return  string|boolean
+     *
+     * @warning Some contexts do not pass $config, $context. These
+     *          variables should not be used without checking HTMLPurifier_Length
+     */
+    public function validate($ratio, $config, $context)
+    {
+        $ratio = $this->parseCDATA($ratio);
+
+        $parts = explode('/', $ratio, 2);
+        $length = count($parts);
+
+        if ($length < 1 || $length > 2) {
+            return false;
+        }
+
+        $num = new \HTMLPurifier_AttrDef_CSS_Number();
+
+        if ($length === 1) {
+            return $num->validate($parts[0], $config, $context);
+        }
+
+        $num1 = $num->validate($parts[0], $config, $context);
+        $num2 = $num->validate($parts[1], $config, $context);
+
+        if ($num1 === false || $num2 === false) {
+            return false;
+        }
+
+        return $num1 . '/' . $num2;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 7 - 13
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php

@@ -63,24 +63,18 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
         // This doesn't match I18N domain names, but we don't have proper IRI support,
         // so force users to insert Punycode.
 
-        // There is not a good sense in which underscores should be
-        // allowed, since it's technically not! (And if you go as
-        // far to allow everything as specified by the DNS spec...
-        // well, that's literally everything, modulo some space limits
-        // for the components and the overall name (which, by the way,
-        // we are NOT checking!).  So we (arbitrarily) decide this:
-        // let's allow underscores wherever we would have allowed
-        // hyphens, if they are enabled.  This is a pretty good match
-        // for browser behavior, for example, a large number of browsers
-        // cannot handle foo_.example.com, but foo_bar.example.com is
-        // fairly well supported.
+        // Underscores defined as Unreserved Characters in RFC 3986 are
+        // allowed in a URI. There are cases where we want to consider a
+        // URI containing "_" such as "_dmarc.example.com".
+        // Underscores are not allowed in the default. If you want to
+        // allow it, set Core.AllowHostnameUnderscore to true.
         $underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : '';
 
         // Based off of RFC 1738, but amended so that
         // as per RFC 3696, the top label need only not be all numeric.
         // The productions describing this are:
         $a   = '[a-z]';     // alpha
-        $an  = '[a-z0-9]';  // alphanum
+        $an  = "[a-z0-9$underscore]";  // alphanum
         $and = "[a-z0-9-$underscore]"; // alphanum | "-"
         // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
         $domainlabel = "$an(?:$and*$an)?";
@@ -106,7 +100,7 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
         // If we have Net_IDNA2 support, we can support IRIs by
         // punycoding them. (This is the most portable thing to do,
         // since otherwise we have to assume browsers support
-        } elseif ($config->get('Core.EnableIDNA')) {
+        } elseif ($config->get('Core.EnableIDNA') && class_exists('Net_IDNA2')) {
             $idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true));
             // we need to encode each period separately
             $parts = explode('.', $string);

+ 5 - 1
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php

@@ -33,7 +33,11 @@ class HTMLPurifier_AttrTransform_TargetBlank extends HTMLPurifier_AttrTransform
 
         // XXX Kind of inefficient
         $url = $this->parser->parse($attr['href']);
-        $scheme = $url->getSchemeObj($config, $context);
+        
+        // Ignore invalid schemes (e.g. `javascript:`)
+        if (!($scheme = $url->getSchemeObj($config, $context))) {
+            return $attr;
+        }
 
         if ($scheme->browsable && !$url->isBenign($config, $context)) {
             $attr['target'] = '_blank';

+ 4 - 37
vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php

@@ -79,44 +79,11 @@ class HTMLPurifier_Bootstrap
     public static function registerAutoload()
     {
         $autoload = array('HTMLPurifier_Bootstrap', 'autoload');
-        if (($funcs = spl_autoload_functions()) === false) {
+        if (spl_autoload_functions() === false) {
             spl_autoload_register($autoload);
-        } elseif (function_exists('spl_autoload_unregister')) {
-            if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
-                // prepend flag exists, no need for shenanigans
-                spl_autoload_register($autoload, true, true);
-            } else {
-                $buggy  = version_compare(PHP_VERSION, '5.2.11', '<');
-                $compat = version_compare(PHP_VERSION, '5.1.2', '<=') &&
-                          version_compare(PHP_VERSION, '5.1.0', '>=');
-                foreach ($funcs as $func) {
-                    if ($buggy && is_array($func)) {
-                        // :TRICKY: There are some compatibility issues and some
-                        // places where we need to error out
-                        $reflector = new ReflectionMethod($func[0], $func[1]);
-                        if (!$reflector->isStatic()) {
-                            throw new Exception(
-                                'HTML Purifier autoloader registrar is not compatible
-                                with non-static object methods due to PHP Bug #44144;
-                                Please do not use HTMLPurifier.autoload.php (or any
-                                file that includes this file); instead, place the code:
-                                spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\'))
-                                after your own autoloaders.'
-                            );
-                        }
-                        // Suprisingly, spl_autoload_register supports the
-                        // Class::staticMethod callback format, although call_user_func doesn't
-                        if ($compat) {
-                            $func = implode('::', $func);
-                        }
-                    }
-                    spl_autoload_unregister($func);
-                }
-                spl_autoload_register($autoload);
-                foreach ($funcs as $func) {
-                    spl_autoload_register($func);
-                }
-            }
+        } else {
+            // prepend flag exists, no need for shenanigans
+            spl_autoload_register($autoload, true, true);
         }
     }
 }

+ 112 - 96
vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php

@@ -13,7 +13,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
      * Assoc array of attribute name to definition object.
      * @type HTMLPurifier_AttrDef[]
      */
-    public $info = array();
+    public $info = [];
 
     /**
      * Constructs the info array.  The meat of this class.
@@ -22,7 +22,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
     protected function doSetup($config)
     {
         $this->info['text-align'] = new HTMLPurifier_AttrDef_Enum(
-            array('left', 'right', 'center', 'justify'),
+            ['left', 'right', 'center', 'justify'],
             false
         );
 
@@ -31,7 +31,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
             $this->info['border-right-style'] =
             $this->info['border-left-style'] =
             $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum(
-                array(
+                [
                     'none',
                     'hidden',
                     'dotted',
@@ -42,42 +42,42 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
                     'ridge',
                     'inset',
                     'outset'
-                ),
+                ],
                 false
             );
 
         $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style);
 
         $this->info['clear'] = new HTMLPurifier_AttrDef_Enum(
-            array('none', 'left', 'right', 'both'),
+            ['none', 'left', 'right', 'both'],
             false
         );
         $this->info['float'] = new HTMLPurifier_AttrDef_Enum(
-            array('none', 'left', 'right'),
+            ['none', 'left', 'right'],
             false
         );
         $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum(
-            array('normal', 'italic', 'oblique'),
+            ['normal', 'italic', 'oblique'],
             false
         );
         $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum(
-            array('normal', 'small-caps'),
+            ['normal', 'small-caps'],
             false
         );
 
         $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
-                new HTMLPurifier_AttrDef_Enum(array('none')),
+            [
+                new HTMLPurifier_AttrDef_Enum(['none']),
                 new HTMLPurifier_AttrDef_CSS_URI()
-            )
+            ]
         );
 
         $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum(
-            array('inside', 'outside'),
+            ['inside', 'outside'],
             false
         );
         $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum(
-            array(
+            [
                 'disc',
                 'circle',
                 'square',
@@ -87,7 +87,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
                 'lower-alpha',
                 'upper-alpha',
                 'none'
-            ),
+            ],
             false
         );
         $this->info['list-style-image'] = $uri_or_none;
@@ -95,34 +95,32 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
         $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config);
 
         $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum(
-            array('capitalize', 'uppercase', 'lowercase', 'none'),
+            ['capitalize', 'uppercase', 'lowercase', 'none'],
             false
         );
         $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color();
 
         $this->info['background-image'] = $uri_or_none;
         $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum(
-            array('repeat', 'repeat-x', 'repeat-y', 'no-repeat')
+            ['repeat', 'repeat-x', 'repeat-y', 'no-repeat']
         );
         $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum(
-            array('scroll', 'fixed')
+            ['scroll', 'fixed']
         );
         $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition();
 
         $this->info['background-size'] = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_Enum(
-                    array(
+                    [
                         'auto',
                         'cover',
                         'contain',
-                        'initial',
-                        'inherit',
-                    )
+                    ]
                 ),
                 new HTMLPurifier_AttrDef_CSS_Percentage(),
                 new HTMLPurifier_AttrDef_CSS_Length()
-            )
+            ]
         );
 
         $border_color =
@@ -131,10 +129,10 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
             $this->info['border-left-color'] =
             $this->info['border-right-color'] =
             $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(
-                array(
-                    new HTMLPurifier_AttrDef_Enum(array('transparent')),
+                [
+                    new HTMLPurifier_AttrDef_Enum(['transparent']),
                     new HTMLPurifier_AttrDef_CSS_Color()
-                )
+                ]
             );
 
         $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config);
@@ -146,32 +144,32 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
             $this->info['border-bottom-width'] =
             $this->info['border-left-width'] =
             $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(
-                array(
-                    new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')),
+                [
+                    new HTMLPurifier_AttrDef_Enum(['thin', 'medium', 'thick']),
                     new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative
-                )
+                ]
             );
 
         $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width);
 
         $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
-                new HTMLPurifier_AttrDef_Enum(array('normal')),
+            [
+                new HTMLPurifier_AttrDef_Enum(['normal']),
                 new HTMLPurifier_AttrDef_CSS_Length()
-            )
+            ]
         );
 
         $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
-                new HTMLPurifier_AttrDef_Enum(array('normal')),
+            [
+                new HTMLPurifier_AttrDef_Enum(['normal']),
                 new HTMLPurifier_AttrDef_CSS_Length()
-            )
+            ]
         );
 
         $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_Enum(
-                    array(
+                    [
                         'xx-small',
                         'x-small',
                         'small',
@@ -181,20 +179,20 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
                         'xx-large',
                         'larger',
                         'smaller'
-                    )
+                    ]
                 ),
                 new HTMLPurifier_AttrDef_CSS_Percentage(),
                 new HTMLPurifier_AttrDef_CSS_Length()
-            )
+            ]
         );
 
         $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
-                new HTMLPurifier_AttrDef_Enum(array('normal')),
+            [
+                new HTMLPurifier_AttrDef_Enum(['normal']),
                 new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives
                 new HTMLPurifier_AttrDef_CSS_Length('0'),
                 new HTMLPurifier_AttrDef_CSS_Percentage(true)
-            )
+            ]
         );
 
         $margin =
@@ -202,11 +200,11 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
             $this->info['margin-bottom'] =
             $this->info['margin-left'] =
             $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(
-                array(
+                [
                     new HTMLPurifier_AttrDef_CSS_Length(),
                     new HTMLPurifier_AttrDef_CSS_Percentage(),
-                    new HTMLPurifier_AttrDef_Enum(array('auto'))
-                )
+                    new HTMLPurifier_AttrDef_Enum(['auto'])
+                ]
             );
 
         $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin);
@@ -217,41 +215,40 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
             $this->info['padding-bottom'] =
             $this->info['padding-left'] =
             $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(
-                array(
+                [
                     new HTMLPurifier_AttrDef_CSS_Length('0'),
                     new HTMLPurifier_AttrDef_CSS_Percentage(true)
-                )
+                ]
             );
 
         $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding);
 
         $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_CSS_Length(),
                 new HTMLPurifier_AttrDef_CSS_Percentage()
-            )
+            ]
         );
 
         $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_CSS_Length('0'),
                 new HTMLPurifier_AttrDef_CSS_Percentage(true),
-                new HTMLPurifier_AttrDef_Enum(array('auto', 'initial', 'inherit'))
-            )
+                new HTMLPurifier_AttrDef_Enum(['auto'])
+            ]
         );
         $trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_CSS_Length('0'),
                 new HTMLPurifier_AttrDef_CSS_Percentage(true),
-                new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit'))
-            )
+            ]
         );
         $trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_CSS_Length('0'),
                 new HTMLPurifier_AttrDef_CSS_Percentage(true),
-                new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit'))
-            )
+                new HTMLPurifier_AttrDef_Enum(['none'])
+            ]
         );
         $max = $config->get('CSS.MaxImgLength');
 
@@ -263,10 +260,10 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
                     'img',
                     // For img tags:
                     new HTMLPurifier_AttrDef_CSS_Composite(
-                        array(
+                        [
                             new HTMLPurifier_AttrDef_CSS_Length('0', $max),
-                            new HTMLPurifier_AttrDef_Enum(array('auto'))
-                        )
+                            new HTMLPurifier_AttrDef_Enum(['auto'])
+                        ]
                     ),
                     // For everyone else:
                     $trusted_wh
@@ -278,12 +275,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
                 new HTMLPurifier_AttrDef_Switch(
                     'img',
                     // For img tags:
-                    new HTMLPurifier_AttrDef_CSS_Composite(
-                        array(
-                            new HTMLPurifier_AttrDef_CSS_Length('0', $max),
-                            new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit'))
-                        )
-                    ),
+                    new HTMLPurifier_AttrDef_CSS_Length('0', $max),
                     // For everyone else:
                     $trusted_min_wh
                 );
@@ -295,22 +287,46 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
                     'img',
                     // For img tags:
                     new HTMLPurifier_AttrDef_CSS_Composite(
-                        array(
+                        [
                             new HTMLPurifier_AttrDef_CSS_Length('0', $max),
-                            new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit'))
-                        )
+                            new HTMLPurifier_AttrDef_Enum(['none'])
+                        ]
                     ),
                     // For everyone else:
                     $trusted_max_wh
                 );
 
+        $this->info['aspect-ratio'] = new HTMLPurifier_AttrDef_CSS_Multiple(
+            new HTMLPurifier_AttrDef_CSS_Composite([
+                new HTMLPurifier_AttrDef_CSS_Ratio(),
+                new HTMLPurifier_AttrDef_Enum(['auto']),
+            ])
+        );
+
+        // text-decoration and related shorthands
         $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();
 
+        $this->info['text-decoration-line'] = new HTMLPurifier_AttrDef_Enum(
+            ['none', 'underline', 'overline', 'line-through']
+        );
+
+        $this->info['text-decoration-style'] = new HTMLPurifier_AttrDef_Enum(
+            ['solid', 'double', 'dotted', 'dashed', 'wavy']
+        );
+
+        $this->info['text-decoration-color'] = new HTMLPurifier_AttrDef_CSS_Color();
+
+        $this->info['text-decoration-thickness'] = new HTMLPurifier_AttrDef_CSS_Composite([
+            new HTMLPurifier_AttrDef_CSS_Length(),
+            new HTMLPurifier_AttrDef_CSS_Percentage(),
+            new HTMLPurifier_AttrDef_Enum(['auto', 'from-font'])
+        ]);
+
         $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily();
 
         // this could use specialized code
         $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum(
-            array(
+            [
                 'normal',
                 'bold',
                 'bolder',
@@ -324,7 +340,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
                 '700',
                 '800',
                 '900'
-            ),
+            ],
             false
         );
 
@@ -340,21 +356,21 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
         $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config);
 
         $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(
-            array('collapse', 'separate')
+            ['collapse', 'separate']
         );
 
         $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(
-            array('top', 'bottom')
+            ['top', 'bottom']
         );
 
         $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(
-            array('auto', 'fixed')
+            ['auto', 'fixed']
         );
 
         $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_Enum(
-                    array(
+                    [
                         'baseline',
                         'sub',
                         'super',
@@ -363,11 +379,11 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
                         'middle',
                         'bottom',
                         'text-bottom'
-                    )
+                    ]
                 ),
                 new HTMLPurifier_AttrDef_CSS_Length(),
                 new HTMLPurifier_AttrDef_CSS_Percentage()
-            )
+            ]
         );
 
         $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2);
@@ -375,7 +391,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
         // These CSS properties don't work on many browsers, but we live
         // in THE FUTURE!
         $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(
-            array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line')
+            ['nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line']
         );
 
         if ($config->get('CSS.Proprietary')) {
@@ -422,21 +438,21 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
         // more CSS3
         $this->info['page-break-after'] =
         $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum(
-            array(
+            [
                 'auto',
                 'always',
                 'avoid',
                 'left',
                 'right'
-            )
+            ]
         );
-        $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid'));
+        $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(['auto', 'avoid']);
 
         $border_radius = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_CSS_Percentage(true), // disallow negative
                 new HTMLPurifier_AttrDef_CSS_Length('0') // disallow negative
-            ));
+            ]);
 
         $this->info['border-top-left-radius'] =
         $this->info['border-top-right-radius'] =
@@ -453,7 +469,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
     protected function doSetupTricky($config)
     {
         $this->info['display'] = new HTMLPurifier_AttrDef_Enum(
-            array(
+            [
                 'inline',
                 'block',
                 'list-item',
@@ -472,12 +488,12 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
                 'table-cell',
                 'table-caption',
                 'none'
-            )
+            ]
         );
         $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(
-            array('visible', 'hidden', 'collapse')
+            ['visible', 'hidden', 'collapse']
         );
-        $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll'));
+        $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(['visible', 'hidden', 'auto', 'scroll']);
         $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
     }
 
@@ -487,23 +503,23 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
     protected function doSetupTrusted($config)
     {
         $this->info['position'] = new HTMLPurifier_AttrDef_Enum(
-            array('static', 'relative', 'absolute', 'fixed')
+            ['static', 'relative', 'absolute', 'fixed']
         );
         $this->info['top'] =
         $this->info['left'] =
         $this->info['right'] =
         $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_CSS_Length(),
                 new HTMLPurifier_AttrDef_CSS_Percentage(),
-                new HTMLPurifier_AttrDef_Enum(array('auto')),
-            )
+                new HTMLPurifier_AttrDef_Enum(['auto']),
+            ]
         );
         $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite(
-            array(
+            [
                 new HTMLPurifier_AttrDef_Integer(),
-                new HTMLPurifier_AttrDef_Enum(array('auto')),
-            )
+                new HTMLPurifier_AttrDef_Enum(['auto']),
+            ]
         );
     }
 

+ 3 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php

@@ -190,6 +190,9 @@ class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef
             $current_tr_tbody = null;
 
             foreach($content as $node) {
+                if (!isset($node->name)) {
+                    continue;
+                }
                 switch ($node->name) {
                 case 'tbody':
                     $current_tr_tbody = null;

+ 1 - 1
vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php

@@ -21,7 +21,7 @@ class HTMLPurifier_Config
      * HTML Purifier's version
      * @type string
      */
-    public $version = '4.15.0';
+    public $version = '4.18.0';
 
     /**
      * Whether or not to automatically finalize

File diff suppressed because it is too large
+ 0 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser


+ 10 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveBlanks.txt

@@ -0,0 +1,10 @@
+Core.RemoveBlanks
+TYPE: bool
+DEFAULT: false
+VERSION: 4.18
+--DESCRIPTION--
+<p>
+    If set to true, blank nodes will be removed. This can be useful for maintaining
+    backwards compatibility when upgrading from previous versions of PHP.
+</p>
+--# vim: et sw=4 sts=4

+ 6 - 5
vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php

@@ -287,13 +287,14 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
             } elseif (filegroup($dir) === posix_getgid()) {
                 $chmod = $chmod | 0070;
             } else {
-                // PHP's probably running as nobody, so we'll
-                // need to give global permissions
-                $chmod = $chmod | 0777;
+              // PHP's probably running as nobody, it is
+              // not obvious how to fix this (777 is probably
+              // bad if you are multi-user), let the user figure it out
+                $chmod = null;
             }
             trigger_error(
-                'Directory ' . $dir . ' not writable, ' .
-                'please chmod to ' . decoct($chmod),
+                'Directory ' . $dir . ' not writable. ' .
+                ($chmod === null ? '' : 'Please chmod to ' . decoct($chmod)),
                 E_USER_WARNING
             );
         } else {

+ 1 - 1
vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php

@@ -71,7 +71,7 @@ class HTMLPurifier_DefinitionCacheFactory
             return $this->caches[$method][$type];
         }
         if (isset($this->implementations[$method]) &&
-            class_exists($class = $this->implementations[$method], false)) {
+            class_exists($class = $this->implementations[$method])) {
             $cache = new $class($type);
         } else {
             if ($method != 'Serializer') {

+ 2 - 2
vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php

@@ -116,8 +116,8 @@ class HTMLPurifier_EntityParser
     protected function entityCallback($matches)
     {
         $entity = $matches[0];
-        $hex_part = @$matches[1];
-        $dec_part = @$matches[2];
+        $hex_part = isset($matches[1]) ? $matches[1] : null;
+        $dec_part = isset($matches[2]) ? $matches[2] : null;
         $named_part = empty($matches[3]) ? (empty($matches[4]) ? "" : $matches[4]) : $matches[3];
         if ($hex_part !== NULL && $hex_part !== "") {
             return HTMLPurifier_Encoder::unichr(hexdec($hex_part));

+ 172 - 151
vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php

@@ -54,6 +54,11 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
      */
     private $_enum_attrdef;
 
+    /**
+     * @type HTMLPurifier_AttrDef_Enum
+     */
+    private $_universal_attrdef;
+
     public function __construct()
     {
         $this->_tidy = new csstidy();
@@ -70,6 +75,13 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
                 'focus'
             )
         );
+        $this->_universal_attrdef = new HTMLPurifier_AttrDef_Enum(
+            array(
+                'initial',
+                'inherit',
+                'unset',
+            )
+        );
     }
 
     /**
@@ -146,175 +158,184 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
         foreach ($this->_tidy->css as $k => $decls) {
             // $decls are all CSS declarations inside an @ selector
             $new_decls = array();
-            foreach ($decls as $selector => $style) {
-                $selector = trim($selector);
-                if ($selector === '') {
-                    continue;
-                } // should not happen
-                // Parse the selector
-                // Here is the relevant part of the CSS grammar:
-                //
-                // ruleset
-                //   : selector [ ',' S* selector ]* '{' ...
-                // selector
-                //   : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
-                // combinator
-                //   : '+' S*
-                //   : '>' S*
-                // simple_selector
-                //   : element_name [ HASH | class | attrib | pseudo ]*
-                //   | [ HASH | class | attrib | pseudo ]+
-                // element_name
-                //   : IDENT | '*'
-                //   ;
-                // class
-                //   : '.' IDENT
-                //   ;
-                // attrib
-                //   : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
-                //     [ IDENT | STRING ] S* ]? ']'
-                //   ;
-                // pseudo
-                //   : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ]
-                //   ;
-                //
-                // For reference, here are the relevant tokens:
-                //
-                // HASH         #{name}
-                // IDENT        {ident}
-                // INCLUDES     ==
-                // DASHMATCH    |=
-                // STRING       {string}
-                // FUNCTION     {ident}\(
-                //
-                // And the lexical scanner tokens
-                //
-                // name         {nmchar}+
-                // nmchar       [_a-z0-9-]|{nonascii}|{escape}
-                // nonascii     [\240-\377]
-                // escape       {unicode}|\\[^\r\n\f0-9a-f]
-                // unicode      \\{h}}{1,6}(\r\n|[ \t\r\n\f])?
-                // ident        -?{nmstart}{nmchar*}
-                // nmstart      [_a-z]|{nonascii}|{escape}
-                // string       {string1}|{string2}
-                // string1      \"([^\n\r\f\\"]|\\{nl}|{escape})*\"
-                // string2      \'([^\n\r\f\\"]|\\{nl}|{escape})*\'
-                //
-                // We'll implement a subset (in order to reduce attack
-                // surface); in particular:
-                //
-                //      - No Unicode support
-                //      - No escapes support
-                //      - No string support (by proxy no attrib support)
-                //      - element_name is matched against allowed
-                //        elements (some people might find this
-                //        annoying...)
-                //      - Pseudo-elements one of :first-child, :link,
-                //        :visited, :active, :hover, :focus
+            if (is_array($decls)) {
+                foreach ($decls as $selector => $style) {
+                    $selector = trim($selector);
+                    if ($selector === '') {
+                        continue;
+                    } // should not happen
+                    // Parse the selector
+                    // Here is the relevant part of the CSS grammar:
+                    //
+                    // ruleset
+                    //   : selector [ ',' S* selector ]* '{' ...
+                    // selector
+                    //   : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
+                    // combinator
+                    //   : '+' S*
+                    //   : '>' S*
+                    // simple_selector
+                    //   : element_name [ HASH | class | attrib | pseudo ]*
+                    //   | [ HASH | class | attrib | pseudo ]+
+                    // element_name
+                    //   : IDENT | '*'
+                    //   ;
+                    // class
+                    //   : '.' IDENT
+                    //   ;
+                    // attrib
+                    //   : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
+                    //     [ IDENT | STRING ] S* ]? ']'
+                    //   ;
+                    // pseudo
+                    //   : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ]
+                    //   ;
+                    //
+                    // For reference, here are the relevant tokens:
+                    //
+                    // HASH         #{name}
+                    // IDENT        {ident}
+                    // INCLUDES     ==
+                    // DASHMATCH    |=
+                    // STRING       {string}
+                    // FUNCTION     {ident}\(
+                    //
+                    // And the lexical scanner tokens
+                    //
+                    // name         {nmchar}+
+                    // nmchar       [_a-z0-9-]|{nonascii}|{escape}
+                    // nonascii     [\240-\377]
+                    // escape       {unicode}|\\[^\r\n\f0-9a-f]
+                    // unicode      \\{h}}{1,6}(\r\n|[ \t\r\n\f])?
+                    // ident        -?{nmstart}{nmchar*}
+                    // nmstart      [_a-z]|{nonascii}|{escape}
+                    // string       {string1}|{string2}
+                    // string1      \"([^\n\r\f\\"]|\\{nl}|{escape})*\"
+                    // string2      \'([^\n\r\f\\"]|\\{nl}|{escape})*\'
+                    //
+                    // We'll implement a subset (in order to reduce attack
+                    // surface); in particular:
+                    //
+                    //      - No Unicode support
+                    //      - No escapes support
+                    //      - No string support (by proxy no attrib support)
+                    //      - element_name is matched against allowed
+                    //        elements (some people might find this
+                    //        annoying...)
+                    //      - Pseudo-elements one of :first-child, :link,
+                    //        :visited, :active, :hover, :focus
 
-                // handle ruleset
-                $selectors = array_map('trim', explode(',', $selector));
-                $new_selectors = array();
-                foreach ($selectors as $sel) {
-                    // split on +, > and spaces
-                    $basic_selectors = preg_split('/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE);
-                    // even indices are chunks, odd indices are
-                    // delimiters
-                    $nsel = null;
-                    $delim = null; // guaranteed to be non-null after
-                    // two loop iterations
-                    for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) {
-                        $x = $basic_selectors[$i];
-                        if ($i % 2) {
-                            // delimiter
-                            if ($x === ' ') {
-                                $delim = ' ';
-                            } else {
-                                $delim = ' ' . $x . ' ';
-                            }
-                        } else {
-                            // simple selector
-                            $components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE);
-                            $sdelim = null;
-                            $nx = null;
-                            for ($j = 0, $cc = count($components); $j < $cc; $j++) {
-                                $y = $components[$j];
-                                if ($j === 0) {
-                                    if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) {
-                                        $nx = $y;
-                                    } else {
-                                        // $nx stays null; this matters
-                                        // if we don't manage to find
-                                        // any valid selector content,
-                                        // in which case we ignore the
-                                        // outer $delim
-                                    }
-                                } elseif ($j % 2) {
-                                    // set delimiter
-                                    $sdelim = $y;
+                    // handle ruleset
+                    $selectors = array_map('trim', explode(',', $selector));
+                    $new_selectors = array();
+                    foreach ($selectors as $sel) {
+                        // split on +, > and spaces
+                        $basic_selectors = preg_split('/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE);
+                        // even indices are chunks, odd indices are
+                        // delimiters
+                        $nsel = null;
+                        $delim = null; // guaranteed to be non-null after
+                        // two loop iterations
+                        for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) {
+                            $x = $basic_selectors[$i];
+                            if ($i % 2) {
+                                // delimiter
+                                if ($x === ' ') {
+                                    $delim = ' ';
                                 } else {
-                                    $attrdef = null;
-                                    if ($sdelim === '#') {
-                                        $attrdef = $this->_id_attrdef;
-                                    } elseif ($sdelim === '.') {
-                                        $attrdef = $this->_class_attrdef;
-                                    } elseif ($sdelim === ':') {
-                                        $attrdef = $this->_enum_attrdef;
+                                    $delim = ' ' . $x . ' ';
+                                }
+                            } else {
+                                // simple selector
+                                $components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE);
+                                $sdelim = null;
+                                $nx = null;
+                                for ($j = 0, $cc = count($components); $j < $cc; $j++) {
+                                    $y = $components[$j];
+                                    if ($j === 0) {
+                                        if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) {
+                                            $nx = $y;
+                                        } else {
+                                            // $nx stays null; this matters
+                                            // if we don't manage to find
+                                            // any valid selector content,
+                                            // in which case we ignore the
+                                            // outer $delim
+                                        }
+                                    } elseif ($j % 2) {
+                                        // set delimiter
+                                        $sdelim = $y;
                                     } else {
-                                        throw new HTMLPurifier_Exception('broken invariant sdelim and preg_split');
-                                    }
-                                    $r = $attrdef->validate($y, $config, $context);
-                                    if ($r !== false) {
-                                        if ($r !== true) {
-                                            $y = $r;
+                                        $attrdef = null;
+                                        if ($sdelim === '#') {
+                                            $attrdef = $this->_id_attrdef;
+                                        } elseif ($sdelim === '.') {
+                                            $attrdef = $this->_class_attrdef;
+                                        } elseif ($sdelim === ':') {
+                                            $attrdef = $this->_enum_attrdef;
+                                        } else {
+                                            throw new HTMLPurifier_Exception('broken invariant sdelim and preg_split');
                                         }
-                                        if ($nx === null) {
-                                            $nx = '';
+                                        $r = $attrdef->validate($y, $config, $context);
+                                        if ($r !== false) {
+                                            if ($r !== true) {
+                                                $y = $r;
+                                            }
+                                            if ($nx === null) {
+                                                $nx = '';
+                                            }
+                                            $nx .= $sdelim . $y;
                                         }
-                                        $nx .= $sdelim . $y;
                                     }
                                 }
-                            }
-                            if ($nx !== null) {
-                                if ($nsel === null) {
-                                    $nsel = $nx;
+                                if ($nx !== null) {
+                                    if ($nsel === null) {
+                                        $nsel = $nx;
+                                    } else {
+                                        $nsel .= $delim . $nx;
+                                    }
                                 } else {
-                                    $nsel .= $delim . $nx;
+                                    // delimiters to the left of invalid
+                                    // basic selector ignored
                                 }
-                            } else {
-                                // delimiters to the left of invalid
-                                // basic selector ignored
                             }
                         }
-                    }
-                    if ($nsel !== null) {
-                        if (!empty($scopes)) {
-                            foreach ($scopes as $s) {
-                                $new_selectors[] = "$s $nsel";
+                        if ($nsel !== null) {
+                            if (!empty($scopes)) {
+                                foreach ($scopes as $s) {
+                                    $new_selectors[] = "$s $nsel";
+                                }
+                            } else {
+                                $new_selectors[] = $nsel;
                             }
-                        } else {
-                            $new_selectors[] = $nsel;
                         }
                     }
-                }
-                if (empty($new_selectors)) {
-                    continue;
-                }
-                $selector = implode(', ', $new_selectors);
-                foreach ($style as $name => $value) {
-                    if (!isset($css_definition->info[$name])) {
-                        unset($style[$name]);
+                    if (empty($new_selectors)) {
                         continue;
                     }
-                    $def = $css_definition->info[$name];
-                    $ret = $def->validate($value, $config, $context);
-                    if ($ret === false) {
-                        unset($style[$name]);
-                    } else {
-                        $style[$name] = $ret;
+                    $selector = implode(', ', $new_selectors);
+                    foreach ($style as $name => $value) {
+                        if (!isset($css_definition->info[$name])) {
+                            unset($style[$name]);
+                            continue;
+                        }
+                        $uni_ret = $this->_universal_attrdef->validate($value, $config, $context);
+                        if ($uni_ret !== false) {
+                            $style[$name] = $uni_ret;
+                            continue;
+                        }
+                        $def = $css_definition->info[$name];
+                        $ret = $def->validate($value, $config, $context);
+                        if ($ret === false) {
+                            unset($style[$name]);
+                        } else {
+                            $style[$name] = $ret;
+                        }
                     }
+                    $new_decls[$selector] = $style;
                 }
-                $new_decls[$selector] = $style;
+            } else {
+                continue;
             }
             $new_css[$k] = $new_decls;
         }

+ 17 - 11
vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php

@@ -28,22 +28,28 @@ class HTMLPurifier_HTMLModule_Iframe extends HTMLPurifier_HTMLModule
         if ($config->get('HTML.SafeIframe')) {
             $this->safe = true;
         }
+        $attrs = array(
+            'src' => 'URI#embedded',
+            'width' => 'Length',
+            'height' => 'Length',
+            'name' => 'ID',
+            'scrolling' => 'Enum#yes,no,auto',
+            'frameborder' => 'Enum#0,1',
+            'longdesc' => 'URI',
+            'marginheight' => 'Pixels',
+            'marginwidth' => 'Pixels',
+        );
+
+        if ($config->get('HTML.Trusted')) {
+            $attrs['allowfullscreen'] = 'Bool#allowfullscreen';
+        }
+
         $this->addElement(
             'iframe',
             'Inline',
             'Flow',
             'Common',
-            array(
-                'src' => 'URI#embedded',
-                'width' => 'Length',
-                'height' => 'Length',
-                'name' => 'ID',
-                'scrolling' => 'Enum#yes,no,auto',
-                'frameborder' => 'Enum#0,1',
-                'longdesc' => 'URI',
-                'marginheight' => 'Pixels',
-                'marginwidth' => 'Pixels',
-            )
+            $attrs
         );
     }
 }

+ 1 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy.php

@@ -221,6 +221,7 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
      */
     public function makeFixes()
     {
+        return array();
     }
 }
 

+ 1 - 1
vendor/ezyang/htmlpurifier/library/HTMLPurifier/LanguageFactory.php

@@ -109,7 +109,7 @@ class HTMLPurifier_LanguageFactory
         } else {
             $class = 'HTMLPurifier_Language_' . $pcode;
             $file  = $this->dir . '/Language/classes/' . $code . '.php';
-            if (file_exists($file) || class_exists($class, false)) {
+            if (file_exists($file) || class_exists($class)) {
                 $lang = new $class($config, $context);
             } else {
                 // Go fallback

+ 1 - 17
vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer.php

@@ -101,7 +101,7 @@ class HTMLPurifier_Lexer
                         break;
                     }
 
-                    if (class_exists('DOMDocument', false) &&
+                    if (class_exists('DOMDocument') &&
                         method_exists('DOMDocument', 'loadHTML') &&
                         !extension_loaded('domxml')
                     ) {
@@ -269,20 +269,6 @@ class HTMLPurifier_Lexer
         );
     }
 
-    /**
-     * Special Internet Explorer conditional comments should be removed.
-     * @param string $string HTML string to process.
-     * @return string HTML with conditional comments removed.
-     */
-    protected static function removeIEConditional($string)
-    {
-        return preg_replace(
-            '#<!--\[if [^>]+\]>.*?<!\[endif\]-->#si', // probably should generalize for all strings
-            '',
-            $string
-        );
-    }
-
     /**
      * Callback function for escapeCDATA() that does the work.
      *
@@ -323,8 +309,6 @@ class HTMLPurifier_Lexer
         // escape CDATA
         $html = $this->escapeCDATA($html);
 
-        $html = $this->removeIEConditional($html);
-
         // extract body from document if applicable
         if ($config->get('Core.ConvertDocumentToFragment')) {
             $e = false;

+ 3 - 1
vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php

@@ -72,6 +72,9 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
         if ($config->get('Core.AllowParseManyTags') && defined('LIBXML_PARSEHUGE')) {
             $options |= LIBXML_PARSEHUGE;
         }
+        if ($config->get('Core.RemoveBlanks') && defined('LIBXML_NOBLANKS')) {
+            $options |= LIBXML_NOBLANKS;
+        }
 
         set_error_handler(array($this, 'muteErrorHandler'));
         // loadHTML() fails on PHP 5.3 when second parameter is given
@@ -104,7 +107,6 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
      * To iterate is human, to recurse divine - L. Peter Deutsch
      * @param DOMNode $node DOMNode to be tokenized.
      * @param HTMLPurifier_Token[] $tokens   Array-list of already tokenized tokens.
-     * @return HTMLPurifier_Token of node appended to previously passed tokens.
      */
     protected function tokenizeDOM($node, &$tokens, $config)
     {

+ 5 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php

@@ -32,6 +32,11 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
      */
     protected $compress = false;
 
+    /**
+     * @var HTMLPurifier_Config
+     */
+    protected $genConfig;
+
     /**
      * @param string $name Form element name for directives to be stuffed into
      * @param string $doc_url String documentation URL, will have fragment tagged on

+ 1 - 1
vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Tag.php

@@ -44,7 +44,7 @@ abstract class HTMLPurifier_Token_Tag extends HTMLPurifier_Token
         $this->name = ctype_lower($name) ? $name : strtolower($name);
         foreach ($attr as $key => $value) {
             // normalization only necessary when key is not lowercase
-            if (!ctype_lower($key)) {
+            if (!ctype_lower((string)$key)) {
                 $new_key = strtolower($key);
                 if (!isset($attr[$new_key])) {
                     $attr[$new_key] = $attr[$key];

+ 3 - 3
vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/tel.php

@@ -33,11 +33,11 @@ class HTMLPurifier_URIScheme_tel extends HTMLPurifier_URIScheme
         $uri->host     = null;
         $uri->port     = null;
 
-        // Delete all non-numeric characters, non-x characters
+        // Delete all non-numeric characters, commas, and non-x characters
         // from phone number, EXCEPT for a leading plus sign.
-        $uri->path = preg_replace('/(?!^\+)[^\dx]/', '',
+        $uri->path = preg_replace('/(?!^\+)[^\dx,]/', '',
                      // Normalize e(x)tension to lower-case
-                     str_replace('X', 'x', $uri->path));
+                     str_replace('X', 'x', rawurldecode($uri->path)));
 
         return true;
     }

+ 3 - 3
vendor/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php

@@ -261,7 +261,7 @@ class HTMLPurifier_UnitConverter
      */
     private function round($n, $sigfigs)
     {
-        $new_log = (int)floor(log(abs($n), 10)); // Number of digits left of decimal - 1
+        $new_log = (int)floor(log(abs((float)$n), 10)); // Number of digits left of decimal - 1
         $rp = $sigfigs - $new_log - 1; // Number of decimal places needed
         $neg = $n < 0 ? '-' : ''; // Negative sign
         if ($this->bcmath) {
@@ -276,7 +276,7 @@ class HTMLPurifier_UnitConverter
             }
             return $n;
         } else {
-            return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1);
+            return $this->scale(round((float)$n, $sigfigs - $new_log - 1), $rp + 1);
         }
     }
 
@@ -300,7 +300,7 @@ class HTMLPurifier_UnitConverter
             // Now we return it, truncating the zero that was rounded off.
             return substr($precise, 0, -1) . str_repeat('0', -$scale + 1);
         }
-        return sprintf('%.' . $scale . 'f', (float)$r);
+        return number_format((float)$r, $scale, '.', '');
     }
 }
 

+ 65 - 2
vendor/guzzlehttp/guzzle/CHANGELOG.md

@@ -3,6 +3,68 @@
 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
+
+- Adjusted handler selection to use cURL if its version is 7.21.2 or higher, rather than 7.34.0
+
+
+## 7.9.1 - 2024-07-19
+
+### Fixed
+
+- Fix TLS 1.3 check for HTTP/2 requests
+
+
+## 7.9.0 - 2024-07-18
+
+### Changed
+
+- Improve protocol version checks to provide feedback around unsupported protocols
+- Only select the cURL handler by default if 7.34.0 or higher is linked
+- Improved `CurlMultiHandler` to avoid busy wait if possible
+- Dropped support for EOL `guzzlehttp/psr7` v1
+- Improved URI user info redaction in errors
+
+## 7.8.2 - 2024-07-18
+
+### Added
+
+- Support for PHP 8.4
+
+
+## 7.8.1 - 2023-12-03
+
+### Changed
+
+- Updated links in docs to their canonical versions
+- Replaced `call_user_func*` with native calls
+
+
+## 7.8.0 - 2023-08-27
+
+### Added
+
+- Support for PHP 8.3
+- Added automatic closing of handles on `CurlFactory` object destruction
+
+
+## 7.7.1 - 2023-08-27
+
+### Changed
+
+- Remove the need for `AllowDynamicProperties` in `CurlMultiHandler`
+
+
 ## 7.7.0 - 2023-05-21
 
 ### Added
@@ -628,7 +690,8 @@ object).
   * Note: This has been changed in 5.0.3 to now encode query string values by
     default unless the `rawString` argument is provided when setting the query
     string on a URL: Now allowing many more characters to be present in the
-    query string without being percent encoded. See https://tools.ietf.org/html/rfc3986#appendix-A
+    query string without being percent encoded. See
+    https://datatracker.ietf.org/doc/html/rfc3986#appendix-A
 
 
 ## 5.0.1 - 2014-10-16
@@ -1167,7 +1230,7 @@ interfaces.
 
 ## 3.4.0 - 2013-04-11
 
-* Bug fix: URLs are now resolved correctly based on https://tools.ietf.org/html/rfc3986#section-5.2. #289
+* Bug fix: URLs are now resolved correctly based on https://datatracker.ietf.org/doc/html/rfc3986#section-5.2. #289
 * Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289
 * Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263
 * Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264.

+ 6 - 6
vendor/guzzlehttp/guzzle/README.md

@@ -3,7 +3,7 @@
 # Guzzle, PHP HTTP client
 
 [![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases)
-[![Build Status](https://img.shields.io/github/workflow/status/guzzle/guzzle/CI?label=ci%20build&style=flat-square)](https://github.com/guzzle/guzzle/actions?query=workflow%3ACI)
+[![Build Status](https://img.shields.io/github/actions/workflow/status/guzzle/guzzle/ci.yml?label=ci%20build&style=flat-square)](https://github.com/guzzle/guzzle/actions?query=workflow%3ACI)
 [![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle)
 
 Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
@@ -62,11 +62,11 @@ composer require guzzlehttp/guzzle
 
 | Version | Status              | Packagist           | Namespace    | Repo                | Docs                | PSR-7 | PHP Version  |
 |---------|---------------------|---------------------|--------------|---------------------|---------------------|-------|--------------|
-| 3.x     | EOL                 | `guzzle/guzzle`     | `Guzzle`     | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No    | >=5.3.3,<7.0 |
-| 4.x     | EOL                 | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A                 | No    | >=5.4,<7.0   |
-| 5.x     | EOL                 | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No    | >=5.4,<7.4   |
-| 6.x     | Security fixes only | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes   | >=5.5,<8.0   |
-| 7.x     | Latest              | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes   | >=7.2.5,<8.3 |
+| 3.x     | EOL (2016-10-31)    | `guzzle/guzzle`     | `Guzzle`     | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No    | >=5.3.3,<7.0 |
+| 4.x     | EOL (2016-10-31)    | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A                 | No    | >=5.4,<7.0   |
+| 5.x     | EOL (2019-10-31)    | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No    | >=5.4,<7.4   |
+| 6.x     | EOL (2023-10-31)    | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes   | >=5.5,<8.0   |
+| 7.x     | Latest              | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes   | >=7.2.5,<8.5 |
 
 [guzzle-3-repo]: https://github.com/guzzle/guzzle3
 [guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x

+ 8 - 8
vendor/guzzlehttp/guzzle/UPGRADING.md

@@ -27,7 +27,7 @@ Please make sure:
 - Function `GuzzleHttp\Exception\RequestException::getResponseBodySummary` is removed.
   Use `\GuzzleHttp\Psr7\get_message_body_summary` as an alternative.
 - Function `GuzzleHttp\Cookie\CookieJar::getCookieValue` is removed.
-- Request option `exception` is removed. Please use `http_errors`.
+- Request option `exceptions` is removed. Please use `http_errors`.
 - Request option `save_to` is removed. Please use `sink`.
 - Pool option `pool_size` is removed. Please use `concurrency`.
 - We now look for environment variables in the `$_SERVER` super global, due to thread safety issues with `getenv`. We continue to fallback to `getenv` in CLI environments, for maximum compatibility.
@@ -189,11 +189,11 @@ $client = new GuzzleHttp\Client(['handler' => $handler]);
 
 ## POST Requests
 
-This version added the [`form_params`](http://guzzle.readthedocs.org/en/latest/request-options.html#form_params)
+This version added the [`form_params`](https://docs.guzzlephp.org/en/latest/request-options.html#form_params)
 and `multipart` request options. `form_params` is an associative array of
 strings or array of strings and is used to serialize an
 `application/x-www-form-urlencoded` POST request. The
-[`multipart`](http://guzzle.readthedocs.org/en/latest/request-options.html#multipart)
+[`multipart`](https://docs.guzzlephp.org/en/latest/request-options.html#multipart)
 option is now used to send a multipart/form-data POST request.
 
 `GuzzleHttp\Post\PostFile` has been removed. Use the `multipart` option to add
@@ -209,7 +209,7 @@ The `base_url` option has been renamed to `base_uri`.
 
 ## Rewritten Adapter Layer
 
-Guzzle now uses [RingPHP](http://ringphp.readthedocs.org/en/latest) to send
+Guzzle now uses [RingPHP](https://ringphp.readthedocs.org/en/latest) to send
 HTTP requests. The `adapter` option in a `GuzzleHttp\Client` constructor
 is still supported, but it has now been renamed to `handler`. Instead of
 passing a `GuzzleHttp\Adapter\AdapterInterface`, you must now pass a PHP
@@ -575,7 +575,7 @@ You can intercept a request and inject a response using the `intercept()` event
 of a `GuzzleHttp\Event\BeforeEvent`, `GuzzleHttp\Event\CompleteEvent`, and
 `GuzzleHttp\Event\ErrorEvent` event.
 
-See: http://docs.guzzlephp.org/en/latest/events.html
+See: https://docs.guzzlephp.org/en/latest/events.html
 
 ## Inflection
 
@@ -668,9 +668,9 @@ in separate repositories:
 
 The service description layer of Guzzle has moved into two separate packages:
 
-- http://github.com/guzzle/command Provides a high level abstraction over web
+- https://github.com/guzzle/command Provides a high level abstraction over web
   services by representing web service operations using commands.
-- http://github.com/guzzle/guzzle-services Provides an implementation of
+- https://github.com/guzzle/guzzle-services Provides an implementation of
   guzzle/command that provides request serialization and response parsing using
   Guzzle service descriptions.
 
@@ -870,7 +870,7 @@ HeaderInterface (e.g. toArray(), getAll(), etc.).
 3.3 to 3.4
 ----------
 
-Base URLs of a client now follow the rules of https://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs.
+Base URLs of a client now follow the rules of https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2 when merging URLs.
 
 3.2 to 3.3
 ----------

+ 33 - 5
vendor/guzzlehttp/guzzle/composer.json

@@ -50,11 +50,39 @@
             "homepage": "https://github.com/Tobion"
         }
     ],
+    "repositories": [
+        {
+            "type": "package",
+            "package": {
+                "name": "guzzle/client-integration-tests",
+                "version": "v3.0.2",
+                "dist": {
+                    "url": "https://codeload.github.com/guzzle/client-integration-tests/zip/2c025848417c1135031fdf9c728ee53d0a7ceaee",
+                    "type": "zip"
+                },
+                "require": {
+                    "php": "^7.2.5 || ^8.0",
+                    "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.11",
+                    "php-http/message": "^1.0 || ^2.0",
+                    "guzzlehttp/psr7": "^1.7 || ^2.0",
+                    "th3n3rd/cartesian-product": "^0.3"
+                },
+                "autoload": {
+                    "psr-4": {
+                        "Http\\Client\\Tests\\": "src/"
+                    }
+                },
+                "bin": [
+                    "bin/http_test_server"
+                ]
+            }
+        }
+    ],
     "require": {
         "php": "^7.2.5 || ^8.0",
         "ext-json": "*",
-        "guzzlehttp/promises": "^1.5.3 || ^2.0",
-        "guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
+        "guzzlehttp/promises": "^1.5.3 || ^2.0.3",
+        "guzzlehttp/psr7": "^2.7.0",
         "psr/http-client": "^1.0",
         "symfony/deprecation-contracts": "^2.2 || ^3.0"
     },
@@ -63,10 +91,10 @@
     },
     "require-dev": {
         "ext-curl": "*",
-        "bamarni/composer-bin-plugin": "^1.8.1",
-        "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
+        "bamarni/composer-bin-plugin": "^1.8.2",
+        "guzzle/client-integration-tests": "3.0.2",
         "php-http/message-factory": "^1.1",
-        "phpunit/phpunit": "^8.5.29 || ^9.5.23",
+        "phpunit/phpunit": "^8.5.39 || ^9.6.20",
         "psr/log": "^1.1 || ^2.0 || ^3.0"
     },
     "suggest": {

+ 3 - 3
vendor/guzzlehttp/guzzle/src/BodySummarizer.php

@@ -11,7 +11,7 @@ final class BodySummarizer implements BodySummarizerInterface
      */
     private $truncateAt;
 
-    public function __construct(int $truncateAt = null)
+    public function __construct(?int $truncateAt = null)
     {
         $this->truncateAt = $truncateAt;
     }
@@ -22,7 +22,7 @@ final class BodySummarizer implements BodySummarizerInterface
     public function summarize(MessageInterface $message): ?string
     {
         return $this->truncateAt === null
-            ? \GuzzleHttp\Psr7\Message::bodySummary($message)
-            : \GuzzleHttp\Psr7\Message::bodySummary($message, $this->truncateAt);
+            ? Psr7\Message::bodySummary($message)
+            : Psr7\Message::bodySummary($message, $this->truncateAt);
     }
 }

+ 1 - 1
vendor/guzzlehttp/guzzle/src/Client.php

@@ -52,7 +52,7 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
      *
      * @param array $config Client configuration settings.
      *
-     * @see \GuzzleHttp\RequestOptions for a list of available request options.
+     * @see RequestOptions for a list of available request options.
      */
     public function __construct(array $config = [])
     {

+ 13 - 25
vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php

@@ -96,9 +96,6 @@ class CookieJar implements CookieJarInterface
         return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     public function toArray(): array
     {
         return \array_map(static function (SetCookie $cookie): array {
@@ -106,9 +103,6 @@ class CookieJar implements CookieJarInterface
         }, $this->getIterator()->getArrayCopy());
     }
 
-    /**
-     * {@inheritDoc}
-     */
     public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
     {
         if (!$domain) {
@@ -126,25 +120,22 @@ class CookieJar implements CookieJarInterface
             $this->cookies = \array_filter(
                 $this->cookies,
                 static function (SetCookie $cookie) use ($path, $domain): bool {
-                    return !($cookie->matchesPath($path) &&
-                        $cookie->matchesDomain($domain));
+                    return !($cookie->matchesPath($path)
+                        && $cookie->matchesDomain($domain));
                 }
             );
         } else {
             $this->cookies = \array_filter(
                 $this->cookies,
                 static function (SetCookie $cookie) use ($path, $domain, $name) {
-                    return !($cookie->getName() == $name &&
-                        $cookie->matchesPath($path) &&
-                        $cookie->matchesDomain($domain));
+                    return !($cookie->getName() == $name
+                        && $cookie->matchesPath($path)
+                        && $cookie->matchesDomain($domain));
                 }
             );
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     public function clearSessionCookies(): void
     {
         $this->cookies = \array_filter(
@@ -155,9 +146,6 @@ class CookieJar implements CookieJarInterface
         );
     }
 
-    /**
-     * {@inheritDoc}
-     */
     public function setCookie(SetCookie $cookie): bool
     {
         // If the name string is empty (but not 0), ignore the set-cookie
@@ -182,9 +170,9 @@ class CookieJar implements CookieJarInterface
         foreach ($this->cookies as $i => $c) {
             // Two cookies are identical, when their path, and domain are
             // identical.
-            if ($c->getPath() != $cookie->getPath() ||
-                $c->getDomain() != $cookie->getDomain() ||
-                $c->getName() != $cookie->getName()
+            if ($c->getPath() != $cookie->getPath()
+                || $c->getDomain() != $cookie->getDomain()
+                || $c->getName() != $cookie->getName()
             ) {
                 continue;
             }
@@ -255,7 +243,7 @@ class CookieJar implements CookieJarInterface
     /**
      * Computes cookie path following RFC 6265 section 5.1.4
      *
-     * @see https://tools.ietf.org/html/rfc6265#section-5.1.4
+     * @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4
      */
     private function getCookiePathFromRequest(RequestInterface $request): string
     {
@@ -286,10 +274,10 @@ class CookieJar implements CookieJarInterface
         $path = $uri->getPath() ?: '/';
 
         foreach ($this->cookies as $cookie) {
-            if ($cookie->matchesPath($path) &&
-                $cookie->matchesDomain($host) &&
-                !$cookie->isExpired() &&
-                (!$cookie->getSecure() || $scheme === 'https')
+            if ($cookie->matchesPath($path)
+                && $cookie->matchesDomain($host)
+                && !$cookie->isExpired()
+                && (!$cookie->getSecure() || $scheme === 'https')
             ) {
                 $values[] = $cookie->getName().'='
                     .$cookie->getValue();

+ 1 - 0
vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php

@@ -14,6 +14,7 @@ use Psr\Http\Message\ResponseInterface;
  * cookies from a file, database, etc.
  *
  * @see https://docs.python.org/2/library/cookielib.html Inspiration
+ *
  * @extends \IteratorAggregate<SetCookie>
  */
 interface CookieJarInterface extends \Countable, \IteratorAggregate

+ 6 - 2
vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php

@@ -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;
                         }
@@ -420,7 +424,7 @@ class SetCookie
         }
 
         // Remove the leading '.' as per spec in RFC 6265.
-        // https://tools.ietf.org/html/rfc6265#section-5.2.3
+        // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3
         $cookieDomain = \ltrim(\strtolower($cookieDomain), '.');
 
         $domain = \strtolower($domain);
@@ -431,7 +435,7 @@ class SetCookie
         }
 
         // Matching the subdomain according to RFC 6265.
-        // https://tools.ietf.org/html/rfc6265#section-5.1.3
+        // https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3
         if (\filter_var($domain, \FILTER_VALIDATE_IP)) {
             return false;
         }

+ 1 - 1
vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php

@@ -14,7 +14,7 @@ class BadResponseException extends RequestException
         string $message,
         RequestInterface $request,
         ResponseInterface $response,
-        \Throwable $previous = null,
+        ?\Throwable $previous = null,
         array $handlerContext = []
     ) {
         parent::__construct($message, $request, $response, $previous, $handlerContext);

+ 1 - 1
vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php

@@ -25,7 +25,7 @@ class ConnectException extends TransferException implements NetworkExceptionInte
     public function __construct(
         string $message,
         RequestInterface $request,
-        \Throwable $previous = null,
+        ?\Throwable $previous = null,
         array $handlerContext = []
     ) {
         parent::__construct($message, 0, $previous);

+ 6 - 22
vendor/guzzlehttp/guzzle/src/Exception/RequestException.php

@@ -7,7 +7,6 @@ use GuzzleHttp\BodySummarizerInterface;
 use Psr\Http\Client\RequestExceptionInterface;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\UriInterface;
 
 /**
  * HTTP Request exception
@@ -32,8 +31,8 @@ class RequestException extends TransferException implements RequestExceptionInte
     public function __construct(
         string $message,
         RequestInterface $request,
-        ResponseInterface $response = null,
-        \Throwable $previous = null,
+        ?ResponseInterface $response = null,
+        ?\Throwable $previous = null,
         array $handlerContext = []
     ) {
         // Set the code of the exception if the response is set and not future.
@@ -63,10 +62,10 @@ class RequestException extends TransferException implements RequestExceptionInte
      */
     public static function create(
         RequestInterface $request,
-        ResponseInterface $response = null,
-        \Throwable $previous = null,
+        ?ResponseInterface $response = null,
+        ?\Throwable $previous = null,
         array $handlerContext = [],
-        BodySummarizerInterface $bodySummarizer = null
+        ?BodySummarizerInterface $bodySummarizer = null
     ): self {
         if (!$response) {
             return new self(
@@ -90,8 +89,7 @@ class RequestException extends TransferException implements RequestExceptionInte
             $className = __CLASS__;
         }
 
-        $uri = $request->getUri();
-        $uri = static::obfuscateUri($uri);
+        $uri = \GuzzleHttp\Psr7\Utils::redactUserInfo($request->getUri());
 
         // Client Error: `GET /` resulted in a `404 Not Found` response:
         // <html> ... (truncated)
@@ -113,20 +111,6 @@ class RequestException extends TransferException implements RequestExceptionInte
         return new $className($message, $request, $response, $previous, $handlerContext);
     }
 
-    /**
-     * Obfuscates URI if there is a username and a password present
-     */
-    private static function obfuscateUri(UriInterface $uri): UriInterface
-    {
-        $userInfo = $uri->getUserInfo();
-
-        if (false !== ($pos = \strpos($userInfo, ':'))) {
-            return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
-        }
-
-        return $uri;
-    }
-
     /**
      * Get the request that caused the exception
      */

+ 130 - 24
vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php

@@ -11,6 +11,7 @@ use GuzzleHttp\Psr7\LazyOpenStream;
 use GuzzleHttp\TransferStats;
 use GuzzleHttp\Utils;
 use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\UriInterface;
 
 /**
  * Creates curl resources from a request
@@ -46,6 +47,16 @@ class CurlFactory implements CurlFactoryInterface
 
     public function create(RequestInterface $request, array $options): EasyHandle
     {
+        $protocolVersion = $request->getProtocolVersion();
+
+        if ('2' === $protocolVersion || '2.0' === $protocolVersion) {
+            if (!self::supportsHttp2()) {
+                throw new ConnectException('HTTP/2 is supported by the cURL handler, however libcurl is built without HTTP/2 support.', $request);
+            }
+        } elseif ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
+            throw new ConnectException(sprintf('HTTP/%s is not supported by the cURL handler.', $protocolVersion), $request);
+        }
+
         if (isset($options['curl']['body_as_string'])) {
             $options['_body_as_string'] = $options['curl']['body_as_string'];
             unset($options['curl']['body_as_string']);
@@ -72,6 +83,42 @@ class CurlFactory implements CurlFactoryInterface
         return $easy;
     }
 
+    private static function supportsHttp2(): bool
+    {
+        static $supportsHttp2 = null;
+
+        if (null === $supportsHttp2) {
+            $supportsHttp2 = self::supportsTls12()
+                && defined('CURL_VERSION_HTTP2')
+                && (\CURL_VERSION_HTTP2 & \curl_version()['features']);
+        }
+
+        return $supportsHttp2;
+    }
+
+    private static function supportsTls12(): bool
+    {
+        static $supportsTls12 = null;
+
+        if (null === $supportsTls12) {
+            $supportsTls12 = \CURL_SSLVERSION_TLSv1_2 & \curl_version()['features'];
+        }
+
+        return $supportsTls12;
+    }
+
+    private static function supportsTls13(): bool
+    {
+        static $supportsTls13 = null;
+
+        if (null === $supportsTls13) {
+            $supportsTls13 = defined('CURL_SSLVERSION_TLSv1_3')
+                && (\CURL_SSLVERSION_TLSv1_3 & \curl_version()['features']);
+        }
+
+        return $supportsTls13;
+    }
+
     public function release(EasyHandle $easy): void
     {
         $resource = $easy->handle;
@@ -147,7 +194,7 @@ class CurlFactory implements CurlFactoryInterface
             'error' => \curl_error($easy->handle),
             'appconnect_time' => \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME),
         ] + \curl_getinfo($easy->handle);
-        $ctx[self::CURL_VERSION_STR] = \curl_version()['version'];
+        $ctx[self::CURL_VERSION_STR] = self::getCurlVersion();
         $factory->release($easy);
 
         // Retry when nothing is present or when curl failed to rewind.
@@ -158,6 +205,17 @@ class CurlFactory implements CurlFactoryInterface
         return self::createRejection($easy, $ctx);
     }
 
+    private static function getCurlVersion(): string
+    {
+        static $curlVersion = null;
+
+        if (null === $curlVersion) {
+            $curlVersion = \curl_version()['version'];
+        }
+
+        return $curlVersion;
+    }
+
     private static function createRejection(EasyHandle $easy, array $ctx): PromiseInterface
     {
         static $connectionErrors = [
@@ -194,15 +252,22 @@ class CurlFactory implements CurlFactoryInterface
             );
         }
 
+        $uri = $easy->request->getUri();
+
+        $sanitizedError = self::sanitizeCurlError($ctx['error'] ?? '', $uri);
+
         $message = \sprintf(
             'cURL error %s: %s (%s)',
             $ctx['errno'],
-            $ctx['error'],
+            $sanitizedError,
             'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
         );
-        $uriString = (string) $easy->request->getUri();
-        if ($uriString !== '' && false === \strpos($ctx['error'], $uriString)) {
-            $message .= \sprintf(' for %s', $uriString);
+
+        if ('' !== $sanitizedError) {
+            $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($uri)->__toString();
+            if ($redactedUriString !== '' && false === \strpos($sanitizedError, $redactedUriString)) {
+                $message .= \sprintf(' for %s', $redactedUriString);
+            }
         }
 
         // Create a connection exception if it was a specific error code.
@@ -213,6 +278,24 @@ class CurlFactory implements CurlFactoryInterface
         return P\Create::rejectionFor($error);
     }
 
+    private static function sanitizeCurlError(string $error, UriInterface $uri): string
+    {
+        if ('' === $error) {
+            return $error;
+        }
+
+        $baseUri = $uri->withQuery('')->withFragment('');
+        $baseUriString = $baseUri->__toString();
+
+        if ('' === $baseUriString) {
+            return $error;
+        }
+
+        $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($baseUri)->__toString();
+
+        return str_replace($baseUriString, $redactedUriString, $error);
+    }
+
     /**
      * @return array<int|string, mixed>
      */
@@ -232,10 +315,11 @@ class CurlFactory implements CurlFactoryInterface
         }
 
         $version = $easy->request->getProtocolVersion();
-        if ($version == 1.1) {
-            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
-        } elseif ($version == 2.0) {
+
+        if ('2' === $version || '2.0' === $version) {
             $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0;
+        } elseif ('1.1' === $version) {
+            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
         } else {
             $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0;
         }
@@ -256,7 +340,7 @@ class CurlFactory implements CurlFactoryInterface
 
         $method = $easy->request->getMethod();
         if ($method === 'PUT' || $method === 'POST') {
-            // See https://tools.ietf.org/html/rfc7230#section-3.3.2
+            // See https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
             if (!$easy->request->hasHeader('Content-Length')) {
                 $conf[\CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
             }
@@ -367,11 +451,11 @@ class CurlFactory implements CurlFactoryInterface
                     // If it's a directory or a link to a directory use CURLOPT_CAPATH.
                     // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
                     if (
-                        \is_dir($options['verify']) ||
-                        (
-                            \is_link($options['verify']) === true &&
-                            ($verifyLink = \readlink($options['verify'])) !== false &&
-                            \is_dir($verifyLink)
+                        \is_dir($options['verify'])
+                        || (
+                            \is_link($options['verify']) === true
+                            && ($verifyLink = \readlink($options['verify'])) !== false
+                            && \is_dir($verifyLink)
                         )
                     ) {
                         $conf[\CURLOPT_CAPATH] = $options['verify'];
@@ -390,8 +474,10 @@ class CurlFactory implements CurlFactoryInterface
                 // The empty string enables all available decoders and implicitly
                 // sets a matching 'Accept-Encoding' header.
                 $conf[\CURLOPT_ENCODING] = '';
-                // But as the user did not specify any acceptable encodings we need
-                // to overwrite this implicit header with an empty one.
+                // But as the user did not specify any encoding preference,
+                // let's leave it up to server by preventing curl from sending
+                // the header, which will be interpreted as 'Accept-Encoding: *'.
+                // https://www.rfc-editor.org/rfc/rfc9110#field.accept-encoding
                 $conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
             }
         }
@@ -455,23 +541,35 @@ class CurlFactory implements CurlFactoryInterface
         }
 
         if (isset($options['crypto_method'])) {
-            if (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) {
-                if (!defined('CURL_SSLVERSION_TLSv1_0')) {
-                    throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.0 not supported by your version of cURL');
+            $protocolVersion = $easy->request->getProtocolVersion();
+
+            // If HTTP/2, upgrade TLS 1.0 and 1.1 to 1.2
+            if ('2' === $protocolVersion || '2.0' === $protocolVersion) {
+                if (
+                    \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']
+                    || \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']
+                    || \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']
+                ) {
+                    $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;
+                } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {
+                    if (!self::supportsTls13()) {
+                        throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');
+                    }
+                    $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;
+                } else {
+                    throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
                 }
+            } elseif (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) {
                 $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_0;
             } elseif (\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']) {
-                if (!defined('CURL_SSLVERSION_TLSv1_1')) {
-                    throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.1 not supported by your version of cURL');
-                }
                 $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_1;
             } elseif (\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) {
-                if (!defined('CURL_SSLVERSION_TLSv1_2')) {
+                if (!self::supportsTls12()) {
                     throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.2 not supported by your version of cURL');
                 }
                 $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;
             } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {
-                if (!defined('CURL_SSLVERSION_TLSv1_3')) {
+                if (!self::supportsTls13()) {
                     throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');
                 }
                 $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;
@@ -627,4 +725,12 @@ class CurlFactory implements CurlFactoryInterface
             return \strlen($h);
         };
     }
+
+    public function __destruct()
+    {
+        foreach ($this->handles as $id => $handle) {
+            \curl_close($handle);
+            unset($this->handles[$id]);
+        }
+    }
 }

+ 24 - 3
vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php

@@ -2,6 +2,7 @@
 
 namespace GuzzleHttp\Handler;
 
+use Closure;
 use GuzzleHttp\Promise as P;
 use GuzzleHttp\Promise\Promise;
 use GuzzleHttp\Promise\PromiseInterface;
@@ -15,11 +16,8 @@ use Psr\Http\Message\RequestInterface;
  * associative array of curl option constants mapping to values in the
  * **curl** key of the provided request options.
  *
- * @property resource|\CurlMultiHandle $_mh Internal use only. Lazy loaded multi-handle.
- *
  * @final
  */
-#[\AllowDynamicProperties]
 class CurlMultiHandler
 {
     /**
@@ -56,6 +54,9 @@ class CurlMultiHandler
      */
     private $options = [];
 
+    /** @var resource|\CurlMultiHandle */
+    private $_mh;
+
     /**
      * This handler accepts the following options:
      *
@@ -79,6 +80,10 @@ class CurlMultiHandler
         }
 
         $this->options = $options['options'] ?? [];
+
+        // unsetting the property forces the first access to go through
+        // __get().
+        unset($this->_mh);
     }
 
     /**
@@ -155,6 +160,9 @@ class CurlMultiHandler
             }
         }
 
+        // Run curl_multi_exec in the queue to enable other async tasks to run
+        P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
+
         // Step through the task queue which may add additional requests.
         P\Utils::queue()->run();
 
@@ -165,11 +173,24 @@ class CurlMultiHandler
         }
 
         while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
+            // Prevent busy looping for slow HTTP requests.
+            \curl_multi_select($this->_mh, $this->selectTimeout);
         }
 
         $this->processMessages();
     }
 
+    /**
+     * Runs \curl_multi_exec() inside the event loop, to prevent busy looping
+     */
+    private function tickInQueue(): void
+    {
+        if (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
+            \curl_multi_select($this->_mh, 0);
+            P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
+        }
+    }
+
     /**
      * Runs until all outstanding connections have completed.
      */

+ 4 - 4
vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php

@@ -52,21 +52,21 @@ class MockHandler implements \Countable
      * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled.
      * @param callable|null $onRejected  Callback to invoke when the return value is rejected.
      */
-    public static function createWithMiddleware(array $queue = null, callable $onFulfilled = null, callable $onRejected = null): HandlerStack
+    public static function createWithMiddleware(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null): HandlerStack
     {
         return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
     }
 
     /**
      * The passed in value must be an array of
-     * {@see \Psr\Http\Message\ResponseInterface} objects, Exceptions,
+     * {@see ResponseInterface} objects, Exceptions,
      * callables, or Promises.
      *
      * @param array<int, mixed>|null $queue       The parameters to be passed to the append function, as an indexed array.
      * @param callable|null          $onFulfilled Callback to invoke when the return value is fulfilled.
      * @param callable|null          $onRejected  Callback to invoke when the return value is rejected.
      */
-    public function __construct(array $queue = null, callable $onFulfilled = null, callable $onRejected = null)
+    public function __construct(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null)
     {
         $this->onFulfilled = $onFulfilled;
         $this->onRejected = $onRejected;
@@ -200,7 +200,7 @@ class MockHandler implements \Countable
     private function invokeStats(
         RequestInterface $request,
         array $options,
-        ResponseInterface $response = null,
+        ?ResponseInterface $response = null,
         $reason = null
     ): void {
         if (isset($options['on_stats'])) {

+ 6 - 6
vendor/guzzlehttp/guzzle/src/Handler/Proxy.php

@@ -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
     {

+ 17 - 5
vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php

@@ -40,6 +40,12 @@ class StreamHandler
             \usleep($options['delay'] * 1000);
         }
 
+        $protocolVersion = $request->getProtocolVersion();
+
+        if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
+            throw new ConnectException(sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request);
+        }
+
         $startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
 
         try {
@@ -47,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');
             }
 
@@ -83,8 +95,8 @@ class StreamHandler
         array $options,
         RequestInterface $request,
         ?float $startTime,
-        ResponseInterface $response = null,
-        \Throwable $error = null
+        ?ResponseInterface $response = null,
+        ?\Throwable $error = null
     ): void {
         if (isset($options['on_stats'])) {
             $stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
@@ -273,7 +285,7 @@ class StreamHandler
 
         // HTTP/1.1 streams using the PHP stream wrapper require a
         // Connection: close header
-        if ($request->getProtocolVersion() == '1.1'
+        if ($request->getProtocolVersion() === '1.1'
             && !$request->hasHeader('Connection')
         ) {
             $request = $request->withHeader('Connection', 'close');

+ 1 - 1
vendor/guzzlehttp/guzzle/src/HandlerStack.php

@@ -58,7 +58,7 @@ class HandlerStack
     /**
      * @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler.
      */
-    public function __construct(callable $handler = null)
+    public function __construct(?callable $handler = null)
     {
         $this->handler = $handler;
     }

+ 3 - 3
vendor/guzzlehttp/guzzle/src/Middleware.php

@@ -55,7 +55,7 @@ final class Middleware
      *
      * @return callable(callable): callable Returns a function that accepts the next handler.
      */
-    public static function httpErrors(BodySummarizerInterface $bodySummarizer = null): callable
+    public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null): callable
     {
         return static function (callable $handler) use ($bodySummarizer): callable {
             return static function ($request, array $options) use ($handler, $bodySummarizer) {
@@ -132,7 +132,7 @@ final class Middleware
      *
      * @return callable Returns a function that accepts the next handler.
      */
-    public static function tap(callable $before = null, callable $after = null): callable
+    public static function tap(?callable $before = null, ?callable $after = null): callable
     {
         return static function (callable $handler) use ($before, $after): callable {
             return static function (RequestInterface $request, array $options) use ($handler, $before, $after) {
@@ -176,7 +176,7 @@ final class Middleware
      *
      * @return callable Returns a function that accepts the next handler.
      */
-    public static function retry(callable $decider, callable $delay = null): callable
+    public static function retry(callable $decider, ?callable $delay = null): callable
     {
         return static function (callable $handler) use ($decider, $delay): RetryMiddleware {
             return new RetryMiddleware($decider, $handler, $delay);

+ 1 - 1
vendor/guzzlehttp/guzzle/src/Pool.php

@@ -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.

+ 2 - 2
vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php

@@ -76,8 +76,8 @@ class PrepareBodyMiddleware
 
         $expect = $options['expect'] ?? null;
 
-        // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
-        if ($expect === false || $request->getProtocolVersion() < 1.1) {
+        // Return if disabled or using HTTP/1.0
+        if ($expect === false || $request->getProtocolVersion() === '1.0') {
             return;
         }
 

+ 2 - 2
vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php

@@ -166,8 +166,8 @@ class RedirectMiddleware
         // not forcing RFC compliance, but rather emulating what all browsers
         // would do.
         $statusCode = $response->getStatusCode();
-        if ($statusCode == 303 ||
-            ($statusCode <= 302 && !$options['allow_redirects']['strict'])
+        if ($statusCode == 303
+            || ($statusCode <= 302 && !$options['allow_redirects']['strict'])
         ) {
             $safeMethods = ['GET', 'HEAD', 'OPTIONS'];
             $requestMethod = $request->getMethod();

+ 2 - 4
vendor/guzzlehttp/guzzle/src/RequestOptions.php

@@ -5,9 +5,7 @@ namespace GuzzleHttp;
 /**
  * This class contains a list of built-in Guzzle request options.
  *
- * More documentation for each option can be found at http://guzzlephp.org/.
- *
- * @see http://docs.guzzlephp.org/en/v6/request-options.html
+ * @see https://docs.guzzlephp.org/en/latest/request-options.html
  */
 final class RequestOptions
 {
@@ -63,7 +61,7 @@ final class RequestOptions
      * Specifies whether or not cookies are used in a request or what cookie
      * jar to use or what cookies to send. This option only works if your
      * handler has the `cookie` middleware. Valid values are `false` and
-     * an instance of {@see \GuzzleHttp\Cookie\CookieJarInterface}.
+     * an instance of {@see Cookie\CookieJarInterface}.
      */
     public const COOKIES = 'cookies';
 

+ 2 - 2
vendor/guzzlehttp/guzzle/src/RetryMiddleware.php

@@ -40,7 +40,7 @@ class RetryMiddleware
      *                                                                         and returns the number of
      *                                                                         milliseconds to delay.
      */
-    public function __construct(callable $decider, callable $nextHandler, callable $delay = null)
+    public function __construct(callable $decider, callable $nextHandler, ?callable $delay = null)
     {
         $this->decider = $decider;
         $this->nextHandler = $nextHandler;
@@ -110,7 +110,7 @@ class RetryMiddleware
         };
     }
 
-    private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null): PromiseInterface
+    private function doRetry(RequestInterface $request, array $options, ?ResponseInterface $response = null): PromiseInterface
     {
         $options['delay'] = ($this->delay)(++$options['retries'], $response, $request);
 

+ 10 - 11
vendor/guzzlehttp/guzzle/src/Utils.php

@@ -71,7 +71,7 @@ final class Utils
             return \STDOUT;
         }
 
-        return \GuzzleHttp\Psr7\Utils::tryFopen('php://output', 'w');
+        return Psr7\Utils::tryFopen('php://output', 'w');
     }
 
     /**
@@ -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.
      */
@@ -87,7 +87,7 @@ final class Utils
     {
         $handler = null;
 
-        if (\defined('CURLOPT_CUSTOMREQUEST')) {
+        if (\defined('CURLOPT_CUSTOMREQUEST') && \function_exists('curl_version') && version_compare(curl_version()['version'], '7.21.2') >= 0) {
             if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) {
                 $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
             } elseif (\function_exists('curl_exec')) {
@@ -176,14 +176,13 @@ No system CA bundle could be found in any of the the common system locations.
 PHP versions earlier than 5.6 are not properly configured to use the system's
 CA bundle by default. In order to verify peer certificates, you will need to
 supply the path on disk to a certificate bundle to the 'verify' request
-option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
-need a specific certificate bundle, then Mozilla provides a commonly used CA
-bundle which can be downloaded here (provided by the maintainer of cURL):
-https://curl.haxx.se/ca/cacert.pem. Once
-you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
-ini setting to point to the path to the file, allowing you to omit the 'verify'
-request option. See https://curl.haxx.se/docs/sslcerts.html for more
-information.
+option: https://docs.guzzlephp.org/en/latest/request-options.html#verify. If
+you do not need a specific certificate bundle, then Mozilla provides a commonly
+used CA bundle which can be downloaded here (provided by the maintainer of
+cURL): https://curl.haxx.se/ca/cacert.pem. Once you have a CA bundle available
+on disk, you can set the 'openssl.cafile' PHP ini setting to point to the path
+to the file, allowing you to omit the 'verify' request option. See
+https://curl.haxx.se/docs/sslcerts.html for more information.
 EOT
         );
     }

+ 1 - 1
vendor/guzzlehttp/guzzle/src/functions.php

@@ -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.
  *

+ 43 - 1
vendor/guzzlehttp/promises/CHANGELOG.md

@@ -1,7 +1,49 @@
 # CHANGELOG
 
 
-## 2.0.0 - TBC
+## 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
+
+- Once settled, don't allow further rejection of additional promises
+
+
+## 2.0.3 - 2024-07-18
+
+### Changed
+
+- PHP 8.4 support
+
+
+## 2.0.2 - 2023-12-03
+
+### Changed
+
+- Replaced `call_user_func*` with native calls
+
+
+## 2.0.1 - 2023-08-03
+
+### Changed
+
+- PHP 8.3 support
+
+
+## 2.0.0 - 2023-05-21
 
 ### Added
 

+ 4 - 4
vendor/guzzlehttp/promises/README.md

@@ -38,10 +38,10 @@ composer require guzzlehttp/promises
 
 ## Version Guidance
 
-| Version | Status                 | PHP Version  |
-|---------|------------------------|--------------|
-| 1.x     | Bug and security fixes | >=5.5,<8.3   |
-| 2.x     | Latest                 | >=7.2.5,<8.3 |
+| Version | Status              | PHP Version  |
+|---------|---------------------|--------------|
+| 1.x     | Security fixes only | >=5.5,<8.3   |
+| 2.x     | Latest              | >=7.2.5,<8.5 |
 
 
 ## Quick Start

+ 2 - 2
vendor/guzzlehttp/promises/composer.json

@@ -29,8 +29,8 @@
         "php": "^7.2.5 || ^8.0"
     },
     "require-dev": {
-        "bamarni/composer-bin-plugin": "^1.8.1",
-        "phpunit/phpunit": "^8.5.29 || ^9.5.23"
+        "bamarni/composer-bin-plugin": "^1.8.2",
+        "phpunit/phpunit": "^8.5.39 || ^9.6.20"
     },
     "autoload": {
         "psr-4": {

+ 2 - 2
vendor/guzzlehttp/promises/src/Coroutine.php

@@ -84,8 +84,8 @@ final class Coroutine implements PromiseInterface
     }
 
     public function then(
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         return $this->result->then($onFulfilled, $onRejected);
     }

+ 6 - 11
vendor/guzzlehttp/promises/src/Each.php

@@ -19,14 +19,12 @@ final class Each
      * index, and the aggregate promise. The callback can invoke any necessary
      * side effects and choose to resolve or reject the aggregate if needed.
      *
-     * @param mixed    $iterable    Iterator or array to iterate over.
-     * @param callable $onFulfilled
-     * @param callable $onRejected
+     * @param mixed $iterable Iterator or array to iterate over.
      */
     public static function of(
         $iterable,
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         return (new EachPromise($iterable, [
             'fulfilled' => $onFulfilled,
@@ -44,14 +42,12 @@ final class Each
      *
      * @param mixed        $iterable
      * @param int|callable $concurrency
-     * @param callable     $onFulfilled
-     * @param callable     $onRejected
      */
     public static function ofLimit(
         $iterable,
         $concurrency,
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         return (new EachPromise($iterable, [
             'fulfilled' => $onFulfilled,
@@ -67,12 +63,11 @@ final class Each
      *
      * @param mixed        $iterable
      * @param int|callable $concurrency
-     * @param callable     $onFulfilled
      */
     public static function ofLimitAll(
         $iterable,
         $concurrency,
-        callable $onFulfilled = null
+        ?callable $onFulfilled = null
     ): PromiseInterface {
         return self::ofLimit(
             $iterable,

+ 3 - 5
vendor/guzzlehttp/promises/src/EachPromise.php

@@ -135,7 +135,7 @@ class EachPromise implements PromisorInterface
 
         // Add only up to N pending promises.
         $concurrency = is_callable($this->concurrency)
-            ? call_user_func($this->concurrency, count($this->pending))
+            ? ($this->concurrency)(count($this->pending))
             : $this->concurrency;
         $concurrency = max($concurrency - count($this->pending), 0);
         // Concurrency may be set to 0 to disallow new promises.
@@ -170,8 +170,7 @@ class EachPromise implements PromisorInterface
         $this->pending[$idx] = $promise->then(
             function ($value) use ($idx, $key): void {
                 if ($this->onFulfilled) {
-                    call_user_func(
-                        $this->onFulfilled,
+                    ($this->onFulfilled)(
                         $value,
                         $key,
                         $this->aggregate
@@ -181,8 +180,7 @@ class EachPromise implements PromisorInterface
             },
             function ($reason) use ($idx, $key): void {
                 if ($this->onRejected) {
-                    call_user_func(
-                        $this->onRejected,
+                    ($this->onRejected)(
                         $reason,
                         $key,
                         $this->aggregate

+ 2 - 2
vendor/guzzlehttp/promises/src/FulfilledPromise.php

@@ -31,8 +31,8 @@ class FulfilledPromise implements PromiseInterface
     }
 
     public function then(
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         // Return itself if there is no onFulfilled function.
         if (!$onFulfilled) {

Some files were not shown because too many files changed in this diff