Обновление клиента (apps, 3rdparty, install)

This commit is contained in:
root
2026-03-16 08:42:57 +00:00
parent b8905de237
commit f390426546
3354 changed files with 505213 additions and 3 deletions
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2022-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+23
View File
@@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Php82;
/**
* @internal
*/
trait NoDynamicProperties
{
public function __set(string $name, $value): void
{
throw new \Error('Cannot create dynamic property '.self::class.'::$'.$name);
}
}
+394
View File
@@ -0,0 +1,394 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Php82;
/**
* @author Alexander M. Turek <me@derrabus.de>
* @author Greg Roach <greg@subaqua.co.uk>
*
* @internal
*/
class Php82
{
/**
* Determines if a string matches the ODBC quoting rules.
*
* A valid quoted string begins with a '{', ends with a '}', and has no '}'
* inside of the string that aren't repeated (as to be escaped).
*
* These rules are what .NET also follows.
*
* @see https://github.com/php/php-src/blob/838f6bffff6363a204a2597cbfbaad1d7ee3f2b6/main/php_odbc_utils.c#L31-L57
*/
public static function odbc_connection_string_is_quoted(string $str): bool
{
if ('' === $str || '{' !== $str[0]) {
return false;
}
/* Check for } that aren't doubled up or at the end of the string */
$length = \strlen($str) - 1;
for ($i = 0; $i < $length; ++$i) {
if ('}' !== $str[$i]) {
continue;
}
if ('}' !== $str[++$i]) {
return $i === $length;
}
}
return true;
}
/**
* Determines if a value for a connection string should be quoted.
*
* The ODBC specification mentions:
* "Because of connection string and initialization file grammar, keywords and
* attribute values that contain the characters []{}(),;?*=!@ not enclosed
* with braces should be avoided."
*
* Note that it assumes that the string is *not* already quoted. You should
* check beforehand.
*
* @see https://github.com/php/php-src/blob/838f6bffff6363a204a2597cbfbaad1d7ee3f2b6/main/php_odbc_utils.c#L59-L73
*/
public static function odbc_connection_string_should_quote(string $str): bool
{
return false !== strpbrk($str, '[]{}(),;?*=!@');
}
public static function odbc_connection_string_quote(string $str): string
{
return '{'.str_replace('}', '}}', $str).'}';
}
/**
* Implementation closely based on the original C code - including the GOTOs
* and pointer-style string access.
*
* @see https://github.com/php/php-src/blob/master/Zend/zend_ini.c
*/
public static function ini_parse_quantity(string $value): int
{
// Avoid dependency on ctype_space()
$ctype_space = " \t\v\r\n\f";
$str = 0;
$str_end = \strlen($value);
$digits = $str;
$overflow = false;
/* Ignore leading whitespace, but keep it for error messages. */
while ($digits < $str_end && false !== strpos($ctype_space, $value[$digits])) {
++$digits;
}
/* Ignore trailing whitespace, but keep it for error messages. */
while ($digits < $str_end && false !== strpos($ctype_space, $value[$str_end - 1])) {
--$str_end;
}
if ($digits === $str_end) {
return 0;
}
$is_negative = false;
if ('+' === $value[$digits]) {
++$digits;
} elseif ('-' === $value[$digits]) {
$is_negative = true;
++$digits;
}
if ($value[$digits] < '0' || $value[$digits] > 9) {
$message = sprintf(
'Invalid quantity "%s": no valid leading digits, interpreting as "0" for backwards compatibility',
self::escapeString($value)
);
trigger_error($message, \E_USER_WARNING);
return 0;
}
$base = 10;
$allowed_digits = '0123456789';
if ('0' === $value[$digits] && ($digits + 1 === $str_end || false === strpos($allowed_digits, $value[$digits + 1]))) {
if ($digits + 1 === $str_end) {
return 0;
}
switch ($value[$digits + 1]) {
case 'g':
case 'G':
case 'm':
case 'M':
case 'k':
case 'K':
goto evaluation;
case 'x':
case 'X':
$base = 16;
$allowed_digits = '0123456789abcdefABCDEF';
break;
case 'o':
case 'O':
$base = 8;
$allowed_digits = '01234567';
break;
case 'b':
case 'B':
$base = 2;
$allowed_digits = '01';
break;
default:
$message = sprintf(
'Invalid prefix "0%s", interpreting as "0" for backwards compatibility',
$value[$digits + 1]
);
trigger_error($message, \E_USER_WARNING);
return 0;
}
$digits += 2;
if ($digits === $str_end) {
$message = sprintf(
'Invalid quantity "%s": no digits after base prefix, interpreting as "0" for backwards compatibility',
self::escapeString($value)
);
trigger_error($message, \E_USER_WARNING);
return 0;
}
$digits_consumed = $digits;
/* Ignore leading whitespace. */
while ($digits_consumed < $str_end && false !== strpos($ctype_space, $value[$digits_consumed])) {
++$digits_consumed;
}
if ($digits_consumed !== $str_end && ('+' === $value[$digits_consumed] || '-' === $value[$digits_consumed])) {
++$digits_consumed;
}
if ('0' === $value[$digits_consumed]) {
/* Value is just 0 */
if ($digits_consumed + 1 === $str_end) {
goto evaluation;
}
switch ($value[$digits_consumed + 1]) {
case 'x':
case 'X':
case 'o':
case 'O':
case 'b':
case 'B':
$digits_consumed += 2;
break;
}
}
if ($digits !== $digits_consumed) {
$message = sprintf(
'Invalid quantity "%s": no digits after base prefix, interpreting as "0" for backwards compatibility',
self::escapeString($value)
);
trigger_error($message, \E_USER_WARNING);
return 0;
}
}
evaluation:
if (10 === $base && '0' === $value[$digits]) {
$base = 8;
$allowed_digits = '01234567';
}
while ($digits < $str_end && ' ' === $value[$digits]) {
++$digits;
}
if ($digits < $str_end && '+' === $value[$digits]) {
++$digits;
} elseif ($digits < $str_end && '-' === $value[$digits]) {
$is_negative = true;
$overflow = true;
++$digits;
}
$digits_end = $digits;
while ($digits_end < $str_end && false !== strpos($allowed_digits, $value[$digits_end])) {
++$digits_end;
}
$retval = base_convert(substr($value, $digits, $digits_end - $digits), $base, 10);
if ($is_negative && '0' === $retval) {
$is_negative = false;
$overflow = false;
}
// Check for overflow - remember that -PHP_INT_MIN = 1 + PHP_INT_MAX
if ($is_negative) {
$signed_max = strtr((string) \PHP_INT_MIN, ['-' => '']);
} else {
$signed_max = (string) \PHP_INT_MAX;
}
$max_length = max(\strlen($retval), \strlen($signed_max));
$tmp1 = str_pad($retval, $max_length, '0', \STR_PAD_LEFT);
$tmp2 = str_pad($signed_max, $max_length, '0', \STR_PAD_LEFT);
if ($tmp1 > $tmp2) {
$retval = -1;
$overflow = true;
} elseif ($is_negative) {
$retval = '-'.$retval;
}
$retval = (int) $retval;
if ($digits_end === $digits) {
$message = sprintf(
'Invalid quantity "%s": no valid leading digits, interpreting as "0" for backwards compatibility',
self::escapeString($value)
);
trigger_error($message, \E_USER_WARNING);
return 0;
}
/* Allow for whitespace between integer portion and any suffix character */
while ($digits_end < $str_end && false !== strpos($ctype_space, $value[$digits_end])) {
++$digits_end;
}
/* No exponent suffix. */
if ($digits_end === $str_end) {
goto end;
}
switch ($value[$str_end - 1]) {
case 'g':
case 'G':
$shift = 30;
break;
case 'm':
case 'M':
$shift = 20;
break;
case 'k':
case 'K':
$shift = 10;
break;
default:
/* Unknown suffix */
$invalid = self::escapeString($value);
$interpreted = self::escapeString(substr($value, $str, $digits_end - $str));
$chr = self::escapeString($value[$str_end - 1]);
$message = sprintf(
'Invalid quantity "%s": unknown multiplier "%s", interpreting as "%s" for backwards compatibility',
$invalid,
$chr,
$interpreted
);
trigger_error($message, \E_USER_WARNING);
return $retval;
}
$factor = 1 << $shift;
if (!$overflow) {
if ($retval > 0) {
$overflow = $retval > \PHP_INT_MAX / $factor;
} else {
$overflow = $retval < \PHP_INT_MIN / $factor;
}
}
if (\is_float($retval * $factor)) {
$overflow = true;
$retval <<= $shift;
} else {
$retval *= $factor;
}
if ($digits_end !== $str_end - 1) {
/* More than one character in suffix */
$message = sprintf(
'Invalid quantity "%s", interpreting as "%s%s" for backwards compatibility',
self::escapeString($value),
self::escapeString(substr($value, $str, $digits_end - $str)),
self::escapeString($value[$str_end - 1])
);
trigger_error($message, \E_USER_WARNING);
return $retval;
}
end:
if ($overflow) {
/* Not specifying the resulting value here because the caller may make
* additional conversions. Not specifying the allowed range
* because the caller may do narrower range checks. */
$message = sprintf(
'Invalid quantity "%s": value is out of range, using overflow result for backwards compatibility',
self::escapeString($value)
);
trigger_error($message, \E_USER_WARNING);
}
return $retval;
}
/**
* Escape the string to avoid null bytes and to make non-printable chars visible.
*/
private static function escapeString(string $string): string
{
$escaped = '';
for ($n = 0, $len = \strlen($string); $n < $len; ++$n) {
$c = \ord($string[$n]);
if ($c < 32 || '\\' === $string[$n] || $c > 126) {
switch ($string[$n]) {
case "\n": $escaped .= '\\n'; break;
case "\r": $escaped .= '\\r'; break;
case "\t": $escaped .= '\\t'; break;
case "\f": $escaped .= '\\f'; break;
case "\v": $escaped .= '\\v'; break;
case '\\': $escaped .= '\\\\'; break;
case "\x1B": $escaped .= '\\e'; break;
default:
$escaped .= '\\x'.strtoupper(sprintf('%02x', $c));
}
} else {
$escaped .= $string[$n];
}
}
return $escaped;
}
}
@@ -0,0 +1,50 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Php82\Random\Engine;
use Random\RandomException;
use Symfony\Polyfill\Php82\NoDynamicProperties;
/**
* @author Tim Düsterhus <tim@bastelstu.be>
* @author Anton Smirnov <sandfox@sandfox.me>
*
* @internal
*/
class Secure
{
use NoDynamicProperties;
public function generate(): string
{
try {
return random_bytes(\PHP_INT_SIZE);
} catch (\Exception $e) {
throw new RandomException($e->getMessage(), $e->getCode(), $e->getPrevious());
}
}
public function __sleep(): array
{
throw new \Exception("Serialization of 'Random\Engine\Secure' is not allowed");
}
public function __wakeup(): void
{
throw new \Exception("Unserialization of 'Random\Engine\Secure' is not allowed");
}
public function __clone()
{
throw new \Error('Trying to clone an uncloneable object of class Random\Engine\Secure');
}
}
@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (\PHP_VERSION_ID < 80200) {
#[Attribute(Attribute::TARGET_CLASS)]
final class AllowDynamicProperties
{
public function __construct()
{
}
}
}
@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Random;
if (\PHP_VERSION_ID < 80200) {
class BrokenRandomEngineError extends RandomError
{
}
}
@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Random;
if (\PHP_VERSION_ID < 80200) {
interface CryptoSafeEngine extends Engine
{
}
}
@@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Random;
if (\PHP_VERSION_ID < 80200) {
interface Engine
{
public function generate(): string;
}
}
@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Random\Engine;
use Symfony\Polyfill\Php82 as p;
if (\PHP_VERSION_ID < 80200) {
final class Secure extends p\Random\Engine\Secure implements \Random\CryptoSafeEngine
{
}
}
@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Random;
use Symfony\Polyfill\Php82\NoDynamicProperties;
if (\PHP_VERSION_ID < 80200) {
class RandomError extends \Error
{
use NoDynamicProperties;
}
}
@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Random;
use Symfony\Polyfill\Php82\NoDynamicProperties;
if (\PHP_VERSION_ID < 80200) {
class RandomException extends \Exception
{
use NoDynamicProperties;
}
}
@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (\PHP_VERSION_ID < 80200) {
#[Attribute(Attribute::TARGET_PARAMETER)]
final class SensitiveParameter
{
public function __construct()
{
}
}
}
@@ -0,0 +1,16 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (\PHP_VERSION_ID < 80200) {
final class SensitiveParameterValue extends Symfony\Polyfill\Php82\SensitiveParameterValue
{
}
}
@@ -0,0 +1,47 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Php82;
/**
* @author Tim Düsterhus <duesterhus@woltlab.com>
*
* @internal
*/
class SensitiveParameterValue
{
private $value;
public function __construct($value)
{
$this->value = $value;
}
public function getValue()
{
return $this->value;
}
public function __debugInfo(): array
{
return [];
}
public function __sleep(): array
{
throw new \Exception("Serialization of 'SensitiveParameterValue' is not allowed");
}
public function __wakeup(): void
{
throw new \Exception("Unserialization of 'SensitiveParameterValue' is not allowed");
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Php82 as p;
if (\PHP_VERSION_ID >= 80200) {
return;
}
if (extension_loaded('odbc')) {
if (!function_exists('odbc_connection_string_is_quoted')) {
function odbc_connection_string_is_quoted(string $str): bool { return p\Php82::odbc_connection_string_is_quoted($str); }
}
if (!function_exists('odbc_connection_string_should_quote')) {
function odbc_connection_string_should_quote(string $str): bool { return p\Php82::odbc_connection_string_should_quote($str); }
}
if (!function_exists('odbc_connection_string_quote')) {
function odbc_connection_string_quote(string $str): string { return p\Php82::odbc_connection_string_quote($str); }
}
}
if (!function_exists('ini_parse_quantity')) {
function ini_parse_quantity(string $shorthand): int { return p\Php82::ini_parse_quantity($shorthand); }
}