#413 dependency update

This commit is contained in:
Roland Gruber 2025-03-16 20:12:58 +01:00
parent 55706a30a5
commit 305c08c781
2268 changed files with 122665 additions and 112986 deletions

View file

@ -1137,7 +1137,6 @@ Programs and licenses with other licenses and/or authors than the
main license and authors:
graphics/webauthn.svg F 2017 Duo Security, Inc.
lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei
lib/3rdParty/composer/brick B Benjamin Morel
lib/3rdParty/composer/carbonphp B 2023 Carbon
lib/3rdParty/composer/christian-riesen B Christian Riesen
@ -1145,13 +1144,13 @@ lib/3rdParty/composer/composer B Ni
lib/3rdParty/composer/doctrine B Doctrine Project
lib/3rdParty/composer/duo E Cisco Systems, Inc. and/or its affiliates
lib/3rdParty/composer/facile-it B Thomas Vargiu
lib/3rdParty/composer/fgrosse B 2015 Friedrich Große
lib/3rdParty/composer/firebase F 2011 Neuman Vong
lib/3rdParty/composer/guzzlehttp B 2015 Michael Dowling
lib/3rdParty/composer/http-interop B 2016 Woody Gilk
lib/3rdParty/composer/illuminate B Taylor Otwell
lib/3rdParty/composer/nesbot B Brian Nesbitt
lib/3rdParty/composer/lcobucci B 2017 Luís Cobucci
lib/3rdParty/composer/monolog B 2011 Jordi Boggiano
lib/3rdParty/composer/nesbot B Brian Nesbitt
lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises
lib/3rdParty/composer/php-http B 2015 PHP HTTP Team
lib/3rdParty/composer/phpmailer I
@ -1160,8 +1159,6 @@ lib/3rdParty/composer/psr B PH
lib/3rdParty/composer/ralouphie B 2014 Ralph Khattar
lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs
lib/3rdParty/composer/symfony B 2022 Fabien Potencier
lib/3rdParty/composer/thecodingmachine B TheCodingMachine
lib/3rdParty/composer/voku B 2019 Lars Moelleken
lib/3rdParty/composer/web-auth B 2018 Spomky-Labs
lib/3rdParty/composer/web-token B Florent Morselli
lib/3rdParty/composer/webklex B 2016 Webklex

View file

@ -13,7 +13,6 @@
"require" : {
"web-auth/webauthn-lib" : "^4",
"web-auth/cose-lib": "^v4",
"web-auth/metadata-service": "^4",
"symfony/psr-http-message-bridge" : "^6",
"symfony/http-foundation" : "^6.0",
"symfony/http-client": "^6",

2618
lam/composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1136,7 +1136,6 @@ Programs and licenses with other licenses and/or authors than the
main license and authors:
graphics/webauthn.svg F 2017 Duo Security, Inc.
lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei
lib/3rdParty/composer/brick B Benjamin Morel
lib/3rdParty/composer/carbonphp B 2023 Carbon
lib/3rdParty/composer/christian-riesen B Christian Riesen
@ -1144,13 +1143,13 @@ lib/3rdParty/composer/composer B Ni
lib/3rdParty/composer/doctrine B Doctrine Project
lib/3rdParty/composer/duo E Cisco Systems, Inc. and/or its affiliates
lib/3rdParty/composer/facile-it B Thomas Vargiu
lib/3rdParty/composer/fgrosse B 2015 Friedrich Große
lib/3rdParty/composer/firebase F 2011 Neuman Vong
lib/3rdParty/composer/guzzlehttp B 2015 Michael Dowling
lib/3rdParty/composer/http-interop B 2016 Woody Gilk
lib/3rdParty/composer/illuminate B Taylor Otwell
lib/3rdParty/composer/nesbot B Brian Nesbitt
lib/3rdParty/composer/lcobucci B 2017 Luís Cobucci
lib/3rdParty/composer/monolog B 2011 Jordi Boggiano
lib/3rdParty/composer/nesbot B Brian Nesbitt
lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises
lib/3rdParty/composer/php-http B 2015 PHP HTTP Team
lib/3rdParty/composer/phpmailer I
@ -1159,8 +1158,6 @@ lib/3rdParty/composer/psr B PH
lib/3rdParty/composer/ralouphie B 2014 Ralph Khattar
lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs
lib/3rdParty/composer/symfony B 2022 Fabien Potencier
lib/3rdParty/composer/thecodingmachine B TheCodingMachine
lib/3rdParty/composer/voku B 2019 Lars Moelleken
lib/3rdParty/composer/web-auth B 2018 Spomky-Labs
lib/3rdParty/composer/web-token B Florent Morselli
lib/3rdParty/composer/webklex B 2016 Webklex

View file

@ -1,11 +0,0 @@
Copyright (c) 2011-2013, Benjamin Eberlei
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

View file

@ -1,64 +0,0 @@
{
"name": "beberlei/assert",
"description": "Thin assertion library for input validation in business models.",
"authors": [
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de",
"role": "Lead Developer"
},
{
"name": "Richard Quadling",
"email": "rquadling@gmail.com",
"role": "Collaborator"
}
],
"license": "BSD-2-Clause",
"keywords": [
"assert",
"assertion",
"validation"
],
"config": {
"sort-packages": true
},
"require": {
"php": "^7.1 || ^8.0",
"ext-simplexml": "*",
"ext-mbstring": "*",
"ext-ctype": "*",
"ext-json": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "*",
"phpstan/phpstan": "*",
"phpunit/phpunit": ">=6.0.0",
"yoast/phpunit-polyfills": "^0.1.0"
},
"autoload": {
"psr-4": {
"Assert\\": "lib/Assert"
},
"files": [
"lib/Assert/functions.php"
]
},
"autoload-dev": {
"psr-4": {
"Assert\\Tests\\": "tests/Assert/Tests"
},
"files": [
"tests/Assert/Tests/Fixtures/functions.php"
]
},
"scripts": {
"assert:generate-docs": "php bin/generate_method_docs.php",
"assert:cs-lint": "php-cs-fixer fix --diff -vvv --dry-run",
"assert:cs-fix": "php-cs-fixer fix . -vvv || true",
"assert:sa-code": "vendor/bin/phpstan analyse --configuration=phpstan-code.neon --no-progress --ansi -l 7 bin lib",
"assert:sa-tests": "vendor/bin/phpstan analyse --configuration=phpstan-tests.neon --no-progress --ansi -l 7 tests"
},
"suggest": {
"ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles"
}
}

View file

@ -1,85 +0,0 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
/**
* AssertionChain factory.
*/
abstract class Assert
{
/** @var string */
protected static $lazyAssertionExceptionClass = LazyAssertionException::class;
/** @var string */
protected static $assertionClass = Assertion::class;
/**
* Start validation on a value, returns {@link AssertionChain}.
*
* The invocation of this method starts an assertion chain
* that is happening on the passed value.
*
* @param mixed $value
* @param string|callable|null $defaultMessage
*
* @example
*
* Assert::that($value)->notEmpty()->integer();
* Assert::that($value)->nullOr()->string()->startsWith("Foo");
*
* The assertion chain can be stateful, that means be careful when you reuse
* it. You should never pass around the chain.
*/
public static function that($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain
{
$assertionChain = new AssertionChain($value, $defaultMessage, $defaultPropertyPath);
return $assertionChain->setAssertionClassName(static::$assertionClass);
}
/**
* Start validation on a set of values, returns {@link AssertionChain}.
*
* @param mixed $values
* @param string|callable|null $defaultMessage
*/
public static function thatAll($values, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain
{
return static::that($values, $defaultMessage, $defaultPropertyPath)->all();
}
/**
* Start validation and allow NULL, returns {@link AssertionChain}.
*
* @param mixed $value
* @param string|callable|null $defaultMessage
*/
public static function thatNullOr($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain
{
return static::that($value, $defaultMessage, $defaultPropertyPath)->nullOr();
}
/**
* Create a lazy assertion object.
*/
public static function lazy(): LazyAssertion
{
$lazyAssertion = new LazyAssertion();
return $lazyAssertion
->setAssertClass(\get_called_class())
->setExceptionClass(static::$lazyAssertionExceptionClass);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,247 +0,0 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
use LogicException;
/**
* Chaining builder for assertions.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*
* @method AssertionChain alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric.
* @method AssertionChain base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
* @method AssertionChain between(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit.
* @method AssertionChain betweenExclusive(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit.
* @method AssertionChain betweenLength(int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths.
* @method AssertionChain boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean.
* @method AssertionChain choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices.
* @method AssertionChain choicesNotEmpty(array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content.
* @method AssertionChain classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists.
* @method AssertionChain contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars.
* @method AssertionChain count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count.
* @method AssertionChain date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format.
* @method AssertionChain defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
* @method AssertionChain digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit.
* @method AssertionChain directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists.
* @method AssertionChain e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number.
* @method AssertionChain email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL).
* @method AssertionChain endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars.
* @method AssertionChain eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==).
* @method AssertionChain eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset.
* @method AssertionChain extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded.
* @method AssertionChain extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed.
* @method AssertionChain false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False.
* @method AssertionChain file(string|callable $message = null, string $propertyPath = null) Assert that a file exists.
* @method AssertionChain float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float.
* @method AssertionChain greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit.
* @method AssertionChain greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit.
* @method AssertionChain implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface.
* @method AssertionChain inArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice().
* @method AssertionChain integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer.
* @method AssertionChain integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish.
* @method AssertionChain interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists.
* @method AssertionChain ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address.
* @method AssertionChain ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address.
* @method AssertionChain ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address.
* @method AssertionChain isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array.
* @method AssertionChain isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object.
* @method AssertionChain isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable.
* @method AssertionChain isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable.
* @method AssertionChain isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name.
* @method AssertionChain isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string.
* @method AssertionChain isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object.
* @method AssertionChain isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource.
* @method AssertionChain isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object.
* @method AssertionChain keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array.
* @method AssertionChain keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset().
* @method AssertionChain keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array.
* @method AssertionChain length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length.
* @method AssertionChain lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit.
* @method AssertionChain lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit.
* @method AssertionChain max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit.
* @method AssertionChain maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements.
* @method AssertionChain maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars.
* @method AssertionChain methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object.
* @method AssertionChain min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit.
* @method AssertionChain minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements.
* @method AssertionChain minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long.
* @method AssertionChain noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty.
* @method AssertionChain notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank.
* @method AssertionChain notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars.
* @method AssertionChain notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty.
* @method AssertionChain notEmptyKey(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty.
* @method AssertionChain notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==).
* @method AssertionChain notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices.
* @method AssertionChain notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name.
* @method AssertionChain notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null.
* @method AssertionChain notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex.
* @method AssertionChain notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===).
* @method AssertionChain null(string|callable $message = null, string $propertyPath = null) Assert that value is null.
* @method AssertionChain numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric.
* @method AssertionChain objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists.
* @method AssertionChain phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version.
* @method AssertionChain propertiesExist(array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist.
* @method AssertionChain propertyExists(string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists.
* @method AssertionChain range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers.
* @method AssertionChain readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable.
* @method AssertionChain regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex.
* @method AssertionChain same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===).
* @method AssertionChain satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback.
* @method AssertionChain scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar.
* @method AssertionChain startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars.
* @method AssertionChain string(string|callable $message = null, string $propertyPath = null) Assert that value is a string.
* @method AssertionChain subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name.
* @method AssertionChain true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True.
* @method AssertionChain uniqueValues(string|callable $message = null, string $propertyPath = null) Assert that values in array are unique (using strict equality).
* @method AssertionChain url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL.
* @method AssertionChain uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID.
* @method AssertionChain version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions.
* @method AssertionChain writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable.
*/
class AssertionChain
{
/**
* @var mixed
*/
private $value;
/**
* @var string|callable|null
*/
private $defaultMessage;
/**
* @var string|null
*/
private $defaultPropertyPath;
/**
* Return each assertion as always valid.
*
* @var bool
*/
private $alwaysValid = false;
/**
* Perform assertion on every element of array or traversable.
*
* @var bool
*/
private $all = false;
/** @var string|Assertion Class to use for assertion calls */
private $assertionClassName = 'Assert\Assertion';
/**
* AssertionChain constructor.
*
* @param mixed $value
* @param string|callable|null $defaultMessage
*/
public function __construct($value, $defaultMessage = null, ?string $defaultPropertyPath = null)
{
$this->value = $value;
$this->defaultMessage = $defaultMessage;
$this->defaultPropertyPath = $defaultPropertyPath;
}
/**
* Call assertion on the current value in the chain.
*
* @param string $methodName
* @param array $args
*/
public function __call($methodName, $args): AssertionChain
{
if (true === $this->alwaysValid) {
return $this;
}
try {
$method = new \ReflectionMethod($this->assertionClassName, $methodName);
} catch (\ReflectionException $exception) {
throw new \RuntimeException("Assertion '".$methodName."' does not exist.");
}
\array_unshift($args, $this->value);
$params = $method->getParameters();
foreach ($params as $idx => $param) {
if (isset($args[$idx])) {
continue;
}
switch ($param->getName()) {
case 'message':
$args[$idx] = $this->defaultMessage;
break;
case 'propertyPath':
$args[$idx] = $this->defaultPropertyPath;
break;
}
}
if ($this->all) {
$methodName = 'all'.$methodName;
}
\call_user_func_array([$this->assertionClassName, $methodName], $args);
return $this;
}
/**
* Switch chain into validation mode for an array of values.
*/
public function all(): AssertionChain
{
$this->all = true;
return $this;
}
/**
* Switch chain into mode allowing nulls, ignoring further assertions.
*/
public function nullOr(): AssertionChain
{
if (null === $this->value) {
$this->alwaysValid = true;
}
return $this;
}
/**
* @param string $className
*
* @return $this
*/
public function setAssertionClassName($className): AssertionChain
{
if (!\is_string($className)) {
throw new LogicException('Exception class name must be passed as a string');
}
if (Assertion::class !== $className && !\is_subclass_of($className, Assertion::class)) {
throw new LogicException($className.' is not (a subclass of) '.Assertion::class);
}
$this->assertionClassName = $className;
return $this;
}
}

View file

@ -1,32 +0,0 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
use Throwable;
interface AssertionFailedException extends Throwable
{
/**
* @return string|null
*/
public function getPropertyPath();
/**
* @return mixed
*/
public function getValue();
public function getConstraints(): array;
}

View file

@ -1,74 +0,0 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
class InvalidArgumentException extends \InvalidArgumentException implements AssertionFailedException
{
/**
* @var string|null
*/
private $propertyPath;
/**
* @var mixed
*/
private $value;
/**
* @var array
*/
private $constraints;
public function __construct($message, $code, ?string $propertyPath = null, $value = null, array $constraints = [])
{
parent::__construct($message, $code);
$this->propertyPath = $propertyPath;
$this->value = $value;
$this->constraints = $constraints;
}
/**
* User controlled way to define a sub-property causing
* the failure of a currently asserted objects.
*
* Useful to transport information about the nature of the error
* back to higher layers.
*
* @return string|null
*/
public function getPropertyPath()
{
return $this->propertyPath;
}
/**
* Get the value that caused the assertion to fail.
*
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* Get the constraints that applied to the failed assertion.
*/
public function getConstraints(): array
{
return $this->constraints;
}
}

View file

@ -1,228 +0,0 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
use LogicException;
/**
* Chaining builder for lazy assertions.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*
* @method LazyAssertion alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric.
* @method LazyAssertion base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
* @method LazyAssertion between(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit.
* @method LazyAssertion betweenExclusive(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit.
* @method LazyAssertion betweenLength(int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths.
* @method LazyAssertion boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean.
* @method LazyAssertion choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices.
* @method LazyAssertion choicesNotEmpty(array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content.
* @method LazyAssertion classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists.
* @method LazyAssertion contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars.
* @method LazyAssertion count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count.
* @method LazyAssertion date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format.
* @method LazyAssertion defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
* @method LazyAssertion digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit.
* @method LazyAssertion directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists.
* @method LazyAssertion e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number.
* @method LazyAssertion email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL).
* @method LazyAssertion endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars.
* @method LazyAssertion eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==).
* @method LazyAssertion eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset.
* @method LazyAssertion extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded.
* @method LazyAssertion extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed.
* @method LazyAssertion false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False.
* @method LazyAssertion file(string|callable $message = null, string $propertyPath = null) Assert that a file exists.
* @method LazyAssertion float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float.
* @method LazyAssertion greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit.
* @method LazyAssertion greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit.
* @method LazyAssertion implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface.
* @method LazyAssertion inArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice().
* @method LazyAssertion integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer.
* @method LazyAssertion integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish.
* @method LazyAssertion interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists.
* @method LazyAssertion ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address.
* @method LazyAssertion ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address.
* @method LazyAssertion ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address.
* @method LazyAssertion isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array.
* @method LazyAssertion isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object.
* @method LazyAssertion isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable.
* @method LazyAssertion isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable.
* @method LazyAssertion isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name.
* @method LazyAssertion isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string.
* @method LazyAssertion isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object.
* @method LazyAssertion isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource.
* @method LazyAssertion isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object.
* @method LazyAssertion keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array.
* @method LazyAssertion keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset().
* @method LazyAssertion keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array.
* @method LazyAssertion length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length.
* @method LazyAssertion lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit.
* @method LazyAssertion lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit.
* @method LazyAssertion max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit.
* @method LazyAssertion maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements.
* @method LazyAssertion maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars.
* @method LazyAssertion methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object.
* @method LazyAssertion min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit.
* @method LazyAssertion minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements.
* @method LazyAssertion minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long.
* @method LazyAssertion noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty.
* @method LazyAssertion notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank.
* @method LazyAssertion notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars.
* @method LazyAssertion notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty.
* @method LazyAssertion notEmptyKey(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty.
* @method LazyAssertion notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==).
* @method LazyAssertion notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices.
* @method LazyAssertion notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name.
* @method LazyAssertion notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null.
* @method LazyAssertion notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex.
* @method LazyAssertion notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===).
* @method LazyAssertion null(string|callable $message = null, string $propertyPath = null) Assert that value is null.
* @method LazyAssertion numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric.
* @method LazyAssertion objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists.
* @method LazyAssertion phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version.
* @method LazyAssertion propertiesExist(array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist.
* @method LazyAssertion propertyExists(string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists.
* @method LazyAssertion range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers.
* @method LazyAssertion readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable.
* @method LazyAssertion regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex.
* @method LazyAssertion same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===).
* @method LazyAssertion satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback.
* @method LazyAssertion scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar.
* @method LazyAssertion startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars.
* @method LazyAssertion string(string|callable $message = null, string $propertyPath = null) Assert that value is a string.
* @method LazyAssertion subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name.
* @method LazyAssertion true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True.
* @method LazyAssertion uniqueValues(string|callable $message = null, string $propertyPath = null) Assert that values in array are unique (using strict equality).
* @method LazyAssertion url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL.
* @method LazyAssertion uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID.
* @method LazyAssertion version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions.
* @method LazyAssertion writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable.
* @method LazyAssertion all() Switch chain into validation mode for an array of values.
* @method LazyAssertion nullOr() Switch chain into mode allowing nulls, ignoring further assertions.
*/
class LazyAssertion
{
private $currentChainFailed = false;
private $alwaysTryAll = false;
private $thisChainTryAll = false;
private $currentChain;
private $errors = [];
/** @var string The class to use as AssertionChain factory */
private $assertClass = Assert::class;
/** @var string|LazyAssertionException The class to use for exceptions */
private $exceptionClass = LazyAssertionException::class;
/**
* @param mixed $value
* @param string|callable|null $defaultMessage
*
* @return static
*/
public function that($value, ?string $propertyPath = null, $defaultMessage = null)
{
$this->currentChainFailed = false;
$this->thisChainTryAll = false;
$assertClass = $this->assertClass;
$this->currentChain = $assertClass::that($value, $defaultMessage, $propertyPath);
return $this;
}
/**
* @return static
*/
public function tryAll()
{
if (!$this->currentChain) {
$this->alwaysTryAll = true;
}
$this->thisChainTryAll = true;
return $this;
}
/**
* @param string $method
* @param array $args
*
* @return static
*/
public function __call($method, $args)
{
if (false === $this->alwaysTryAll
&& false === $this->thisChainTryAll
&& true === $this->currentChainFailed
) {
return $this;
}
try {
\call_user_func_array([$this->currentChain, $method], $args);
} catch (AssertionFailedException $e) {
$this->errors[] = $e;
$this->currentChainFailed = true;
}
return $this;
}
/**
* @throws LazyAssertionException
*/
public function verifyNow(): bool
{
if ($this->errors) {
throw \call_user_func([$this->exceptionClass, 'fromErrors'], $this->errors);
}
return true;
}
/**
* @param string $className
*
* @return static
*/
public function setAssertClass(string $className): LazyAssertion
{
if (Assert::class !== $className && !\is_subclass_of($className, Assert::class)) {
throw new LogicException($className.' is not (a subclass of) '.Assert::class);
}
$this->assertClass = $className;
return $this;
}
/**
* @param string $className
*
* @return static
*/
public function setExceptionClass(string $className): LazyAssertion
{
if (LazyAssertionException::class !== $className && !\is_subclass_of($className, LazyAssertionException::class)) {
throw new LogicException($className.' is not (a subclass of) '.LazyAssertionException::class);
}
$this->exceptionClass = $className;
return $this;
}
}

View file

@ -1,53 +0,0 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
class LazyAssertionException extends InvalidArgumentException
{
/**
* @var InvalidArgumentException[]
*/
private $errors = [];
/**
* @param InvalidArgumentException[] $errors
*/
public static function fromErrors(array $errors): self
{
$message = \sprintf('The following %d assertions failed:', \count($errors))."\n";
$i = 1;
foreach ($errors as $error) {
$message .= \sprintf("%d) %s: %s\n", $i++, $error->getPropertyPath(), $error->getMessage());
}
return new static($message, $errors);
}
public function __construct($message, array $errors)
{
parent::__construct($message, 0, null, null);
$this->errors = $errors;
}
/**
* @return InvalidArgumentException[]
*/
public function getErrorExceptions(): array
{
return $this->errors;
}
}

View file

@ -1,72 +0,0 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
/**
* Start validation on a value, returns {@link AssertionChain}.
*
* The invocation of this method starts an assertion chain
* that is happening on the passed value.
*
* @param mixed $value
* @param string|callable|null $defaultMessage
* @param string $defaultPropertyPath
*
* @example
*
* \Assert\that($value)->notEmpty()->integer();
* \Assert\that($value)->nullOr()->string()->startsWith("Foo");
*
* The assertion chain can be stateful, that means be careful when you reuse
* it. You should never pass around the chain.
*/
function that($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain
{
return Assert::that($value, $defaultMessage, $defaultPropertyPath);
}
/**
* Start validation on a set of values, returns {@link AssertionChain}.
*
* @param mixed $values
* @param string|callable|null $defaultMessage
* @param string $defaultPropertyPath
*/
function thatAll($values, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain
{
return Assert::thatAll($values, $defaultMessage, $defaultPropertyPath);
}
/**
* Start validation and allow NULL, returns {@link AssertionChain}.
*
* @param mixed $value
* @param string|callable|null $defaultMessage
* @param string $defaultPropertyPath
*
* @deprecated In favour of Assert::thatNullOr($value, $defaultMessage = null, $defaultPropertyPath = null)
*/
function thatNullOr($value, $defaultMessage = null, ?string $defaultPropertyPath = null): AssertionChain
{
return Assert::thatNullOr($value, $defaultMessage, $defaultPropertyPath);
}
/**
* Create a lazy assertion object.
*/
function lazy(): LazyAssertion
{
return Assert::lazy();
}

View file

@ -2,11 +2,75 @@
All notable changes to this project will be documented in this file.
## [0.12.3](https://github.com/brick/math/releases/tag/0.12.3) - 2025-02-28
✨ **New features**
- `BigDecimal::getPrecision()` Returns the number of significant digits in a decimal number
## [0.12.2](https://github.com/brick/math/releases/tag/0.12.2) - 2025-02-26
⚡️ **Performance improvements**
- Division in `NativeCalculator` is now faster for small divisors, thanks to [@Izumi-kun](https://github.com/Izumi-kun) in [#87](https://github.com/brick/math/pull/87).
👌 **Improvements**
- Add missing `RoundingNecessaryException` to the `@throws` annotation of `BigNumber::of()`
## [0.12.1](https://github.com/brick/math/releases/tag/0.12.1) - 2023-11-29
⚡️ **Performance improvements**
- `BigNumber::of()` is now faster, thanks to [@SebastienDug](https://github.com/SebastienDug) in [#77](https://github.com/brick/math/pull/77).
## [0.12.0](https://github.com/brick/math/releases/tag/0.12.0) - 2023-11-26
💥 **Breaking changes**
- Minimum PHP version is now 8.1
- `RoundingMode` is now an `enum`; if you're type-hinting rounding modes, you need to type-hint against `RoundingMode` instead of `int` now
- `BigNumber` classes do not implement the `Serializable` interface anymore (they use the [new custom object serialization mechanism](https://wiki.php.net/rfc/custom_object_serialization))
- The following breaking changes only affect you if you're creating your own `BigNumber` subclasses:
- the return type of `BigNumber::of()` is now `static`
- `BigNumber` has a new abstract method `from()`
- all `public` and `protected` functions of `BigNumber` are now `final`
## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16
💥 **Breaking changes**
- Minimum PHP version is now 8.0
- Methods accepting a union of types are now strongly typed<sup>*</sup>
- `MathException` now extends `Exception` instead of `RuntimeException`
<sup>* You may now run into type errors if you were passing `Stringable` objects to `of()` or any of the methods
internally calling `of()`, with `strict_types` enabled. You can fix this by casting `Stringable` objects to `string`
first.</sup>
## [0.10.2](https://github.com/brick/math/releases/tag/0.10.2) - 2022-08-11
👌 **Improvements**
- `BigRational::toFloat()` now simplifies the fraction before performing division (#73) thanks to @olsavmic
## [0.10.1](https://github.com/brick/math/releases/tag/0.10.1) - 2022-08-02
✨ **New features**
- `BigInteger::gcdMultiple()` returns the GCD of multiple `BigInteger` numbers
## [0.10.0](https://github.com/brick/math/releases/tag/0.10.0) - 2022-06-18
💥 **Breaking changes**
- Minimum PHP version is now 7.4
## [0.9.3](https://github.com/brick/math/releases/tag/0.9.3) - 2021-08-15
🚀 **Compatibility with PHP 8.1**
- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (thanks @TRowbotham)
- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (#60) thanks @TRowbotham
## [0.9.2](https://github.com/brick/math/releases/tag/0.9.2) - 2021-01-20
@ -16,7 +80,7 @@ All notable changes to this project will be documented in this file.
## [0.9.1](https://github.com/brick/math/releases/tag/0.9.1) - 2020-08-19
✨ New features
**New features**
- `BigInteger::not()` returns the bitwise `NOT` value

View file

@ -1,17 +0,0 @@
# Security Policy
## Supported Versions
Only the last two release streams are supported.
| Version | Supported |
| ------- | ------------------ |
| 0.9.x | :white_check_mark: |
| 0.8.x | :white_check_mark: |
| < 0.8 | :x: |
## Reporting a Vulnerability
To report a security vulnerability, please use the
[Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.

View file

@ -5,22 +5,26 @@
"keywords": [
"Brick",
"Math",
"Mathematics",
"Arbitrary-precision",
"Arithmetic",
"BigInteger",
"BigDecimal",
"BigRational",
"Bignum"
"BigNumber",
"Bignum",
"Decimal",
"Rational",
"Integer"
],
"license": "MIT",
"require": {
"php": "^7.1 || ^8.0",
"ext-json": "*"
"php": "^8.1"
},
"require-dev": {
"phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
"phpunit/phpunit": "^10.1",
"php-coveralls/php-coveralls": "^2.2",
"vimeo/psalm": "4.9.2"
"vimeo/psalm": "6.8.8"
},
"autoload": {
"psr-4": {

View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="6.8.8@1361cd33008feb3ae2b4a93f1860e14e538ec8c2">
<file src="src/BigInteger.php">
<FalsableReturnStatement>
<code><![CDATA[\hex2bin($hex)]]></code>
</FalsableReturnStatement>
<InvalidFalsableReturnType>
<code><![CDATA[string]]></code>
</InvalidFalsableReturnType>
</file>
<file src="src/Exception/DivisionByZeroException.php">
<ClassMustBeFinal>
<code><![CDATA[DivisionByZeroException]]></code>
</ClassMustBeFinal>
</file>
<file src="src/Exception/IntegerOverflowException.php">
<ClassMustBeFinal>
<code><![CDATA[IntegerOverflowException]]></code>
</ClassMustBeFinal>
</file>
<file src="src/Exception/NegativeNumberException.php">
<ClassMustBeFinal>
<code><![CDATA[NegativeNumberException]]></code>
</ClassMustBeFinal>
</file>
<file src="src/Exception/NumberFormatException.php">
<ClassMustBeFinal>
<code><![CDATA[NumberFormatException]]></code>
</ClassMustBeFinal>
</file>
<file src="src/Exception/RoundingNecessaryException.php">
<ClassMustBeFinal>
<code><![CDATA[RoundingNecessaryException]]></code>
</ClassMustBeFinal>
</file>
<file src="src/Internal/Calculator/BcMathCalculator.php">
<ClassMustBeFinal>
<code><![CDATA[BcMathCalculator]]></code>
</ClassMustBeFinal>
</file>
<file src="src/Internal/Calculator/GmpCalculator.php">
<ClassMustBeFinal>
<code><![CDATA[GmpCalculator]]></code>
</ClassMustBeFinal>
</file>
<file src="src/Internal/Calculator/NativeCalculator.php">
<ClassMustBeFinal>
<code><![CDATA[NativeCalculator]]></code>
</ClassMustBeFinal>
<InvalidOperand>
<code><![CDATA[$a * $b]]></code>
<code><![CDATA[$a * 1]]></code>
<code><![CDATA[$a + $b]]></code>
<code><![CDATA[$b * 1]]></code>
<code><![CDATA[$b * 1]]></code>
<code><![CDATA[$blockA * $blockB + $carry]]></code>
<code><![CDATA[$blockA + $blockB]]></code>
<code><![CDATA[$blockA + $blockB + $carry]]></code>
<code><![CDATA[$blockA - $blockB]]></code>
<code><![CDATA[$blockA - $blockB - $carry]]></code>
<code><![CDATA[$carry]]></code>
<code><![CDATA[$mul % $complement]]></code>
<code><![CDATA[$mul - $value]]></code>
<code><![CDATA[$nb - 1]]></code>
<code><![CDATA[$sum += $complement]]></code>
<code><![CDATA[($mul - $value) / $complement]]></code>
<code><![CDATA[($nb - 1) * 10]]></code>
</InvalidOperand>
</file>
</files>

View file

@ -8,6 +8,7 @@ use Brick\Math\Exception\DivisionByZeroException;
use Brick\Math\Exception\MathException;
use Brick\Math\Exception\NegativeNumberException;
use Brick\Math\Internal\Calculator;
use Override;
/**
* Immutable, arbitrary-precision signed decimal numbers.
@ -22,19 +23,15 @@ final class BigDecimal extends BigNumber
* This is a string of digits with an optional leading minus sign.
* No leading zero must be present.
* No leading minus sign must be present if the value is 0.
*
* @var string
*/
private $value;
private readonly string $value;
/**
* The scale (number of digits after the decimal point) of this decimal number.
*
* This must be zero or more.
*
* @var int
*/
private $scale;
private readonly int $scale;
/**
* Protected constructor. Use a factory method to obtain an instance.
@ -49,19 +46,12 @@ final class BigDecimal extends BigNumber
}
/**
* Creates a BigDecimal of the given value.
*
* @param BigNumber|int|float|string $value
*
* @return BigDecimal
*
* @throws MathException If the value cannot be converted to a BigDecimal.
*
* @psalm-pure
*/
public static function of($value) : BigNumber
#[Override]
protected static function from(BigNumber $number): static
{
return parent::of($value)->toBigDecimal();
return $number->toBigDecimal();
}
/**
@ -72,13 +62,11 @@ final class BigDecimal extends BigNumber
* @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger.
* @param int $scale The scale of the number, positive or zero.
*
* @return BigDecimal
*
* @throws \InvalidArgumentException If the scale is negative.
*
* @psalm-pure
*/
public static function ofUnscaledValue($value, int $scale = 0) : BigDecimal
public static function ofUnscaledValue(BigNumber|int|float|string $value, int $scale = 0) : BigDecimal
{
if ($scale < 0) {
throw new \InvalidArgumentException('The scale cannot be negative.');
@ -90,8 +78,6 @@ final class BigDecimal extends BigNumber
/**
* Returns a BigDecimal representing zero, with a scale of zero.
*
* @return BigDecimal
*
* @psalm-pure
*/
public static function zero() : BigDecimal
@ -112,8 +98,6 @@ final class BigDecimal extends BigNumber
/**
* Returns a BigDecimal representing one, with a scale of zero.
*
* @return BigDecimal
*
* @psalm-pure
*/
public static function one() : BigDecimal
@ -134,8 +118,6 @@ final class BigDecimal extends BigNumber
/**
* Returns a BigDecimal representing ten, with a scale of zero.
*
* @return BigDecimal
*
* @psalm-pure
*/
public static function ten() : BigDecimal
@ -160,11 +142,9 @@ final class BigDecimal extends BigNumber
*
* @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal.
*
* @return BigDecimal The result.
*
* @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
*/
public function plus($that) : BigDecimal
public function plus(BigNumber|int|float|string $that) : BigDecimal
{
$that = BigDecimal::of($that);
@ -191,11 +171,9 @@ final class BigDecimal extends BigNumber
*
* @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal.
*
* @return BigDecimal The result.
*
* @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
*/
public function minus($that) : BigDecimal
public function minus(BigNumber|int|float|string $that) : BigDecimal
{
$that = BigDecimal::of($that);
@ -218,11 +196,9 @@ final class BigDecimal extends BigNumber
*
* @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal.
*
* @return BigDecimal The result.
*
* @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal.
*/
public function multipliedBy($that) : BigDecimal
public function multipliedBy(BigNumber|int|float|string $that) : BigDecimal
{
$that = BigDecimal::of($that);
@ -245,14 +221,12 @@ final class BigDecimal extends BigNumber
*
* @param BigNumber|int|float|string $that The divisor.
* @param int|null $scale The desired scale, or null to use the scale of this number.
* @param int $roundingMode An optional rounding mode.
*
* @return BigDecimal
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
*
* @throws \InvalidArgumentException If the scale or rounding mode is invalid.
* @throws MathException If the number is invalid, is zero, or rounding was necessary.
*/
public function dividedBy($that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
{
$that = BigDecimal::of($that);
@ -285,12 +259,10 @@ final class BigDecimal extends BigNumber
*
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
*
* @return BigDecimal The result.
*
* @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero,
* or the result yields an infinite number of digits.
*/
public function exactlyDividedBy($that) : BigDecimal
public function exactlyDividedBy(BigNumber|int|float|string $that) : BigDecimal
{
$that = BigDecimal::of($that);
@ -326,10 +298,6 @@ final class BigDecimal extends BigNumber
*
* The result has a scale of `$this->scale * $exponent`.
*
* @param int $exponent The exponent.
*
* @return BigDecimal The result.
*
* @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
*/
public function power(int $exponent) : BigDecimal
@ -354,17 +322,15 @@ final class BigDecimal extends BigNumber
}
/**
* Returns the quotient of the division of this number by this given one.
* Returns the quotient of the division of this number by the given one.
*
* The quotient has a scale of `0`.
*
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
*
* @return BigDecimal The quotient.
*
* @throws MathException If the divisor is not a valid decimal number, or is zero.
*/
public function quotient($that) : BigDecimal
public function quotient(BigNumber|int|float|string $that) : BigDecimal
{
$that = BigDecimal::of($that);
@ -381,17 +347,15 @@ final class BigDecimal extends BigNumber
}
/**
* Returns the remainder of the division of this number by this given one.
* Returns the remainder of the division of this number by the given one.
*
* The remainder has a scale of `max($this->scale, $that->scale)`.
*
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
*
* @return BigDecimal The remainder.
*
* @throws MathException If the divisor is not a valid decimal number, or is zero.
*/
public function remainder($that) : BigDecimal
public function remainder(BigNumber|int|float|string $that) : BigDecimal
{
$that = BigDecimal::of($that);
@ -418,9 +382,11 @@ final class BigDecimal extends BigNumber
*
* @return BigDecimal[] An array containing the quotient and the remainder.
*
* @psalm-return array{BigDecimal, BigDecimal}
*
* @throws MathException If the divisor is not a valid decimal number, or is zero.
*/
public function quotientAndRemainder($that) : array
public function quotientAndRemainder(BigNumber|int|float|string $that) : array
{
$that = BigDecimal::of($that);
@ -444,10 +410,6 @@ final class BigDecimal extends BigNumber
/**
* Returns the square root of this number, rounded down to the given number of decimals.
*
* @param int $scale
*
* @return BigDecimal
*
* @throws \InvalidArgumentException If the scale is negative.
* @throws NegativeNumberException If this number is negative.
*/
@ -488,10 +450,6 @@ final class BigDecimal extends BigNumber
/**
* Returns a copy of this BigDecimal with the decimal point moved $n places to the left.
*
* @param int $n
*
* @return BigDecimal
*/
public function withPointMovedLeft(int $n) : BigDecimal
{
@ -508,10 +466,6 @@ final class BigDecimal extends BigNumber
/**
* Returns a copy of this BigDecimal with the decimal point moved $n places to the right.
*
* @param int $n
*
* @return BigDecimal
*/
public function withPointMovedRight(int $n) : BigDecimal
{
@ -538,8 +492,6 @@ final class BigDecimal extends BigNumber
/**
* Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part.
*
* @return BigDecimal
*/
public function stripTrailingZeros() : BigDecimal
{
@ -571,8 +523,6 @@ final class BigDecimal extends BigNumber
/**
* Returns the absolute value of this number.
*
* @return BigDecimal
*/
public function abs() : BigDecimal
{
@ -581,18 +531,14 @@ final class BigDecimal extends BigNumber
/**
* Returns the negated value of this number.
*
* @return BigDecimal
*/
public function negated() : BigDecimal
{
return new BigDecimal(Calculator::get()->neg($this->value), $this->scale);
}
/**
* {@inheritdoc}
*/
public function compareTo($that) : int
#[Override]
public function compareTo(BigNumber|int|float|string $that) : int
{
$that = BigNumber::of($that);
@ -609,36 +555,53 @@ final class BigDecimal extends BigNumber
return - $that->compareTo($this);
}
/**
* {@inheritdoc}
*/
#[Override]
public function getSign() : int
{
return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);
}
/**
* @return BigInteger
*/
public function getUnscaledValue() : BigInteger
{
return BigInteger::create($this->value);
return self::newBigInteger($this->value);
}
/**
* @return int
*/
public function getScale() : int
{
return $this->scale;
}
/**
* Returns the number of significant digits in the number.
*
* This is the number of digits to both sides of the decimal point, stripped of leading zeros.
* The sign has no impact on the result.
*
* Examples:
* 0 => 0
* 0.0 => 0
* 123 => 3
* 123.456 => 6
* 0.00123 => 3
* 0.0012300 => 5
*/
public function getPrecision(): int
{
$value = $this->value;
if ($value === '0') {
return 0;
}
$length = \strlen($value);
return ($value[0] === '-') ? $length - 1 : $length;
}
/**
* Returns a string representing the integral part of this decimal number.
*
* Example: `-123.456` => `-123`.
*
* @return string
*/
public function getIntegralPart() : string
{
@ -657,8 +620,6 @@ final class BigDecimal extends BigNumber
* If the scale is zero, an empty string is returned.
*
* Examples: `-123.456` => '456', `123` => ''.
*
* @return string
*/
public function getFractionalPart() : string
{
@ -673,47 +634,37 @@ final class BigDecimal extends BigNumber
/**
* Returns whether this decimal number has a non-zero fractional part.
*
* @return bool
*/
public function hasNonZeroFractionalPart() : bool
{
return $this->getFractionalPart() !== \str_repeat('0', $this->scale);
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBigInteger() : BigInteger
{
$zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0);
return BigInteger::create($zeroScaleDecimal->value);
return self::newBigInteger($zeroScaleDecimal->value);
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBigDecimal() : BigDecimal
{
return $this;
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBigRational() : BigRational
{
$numerator = BigInteger::create($this->value);
$denominator = BigInteger::create('1' . \str_repeat('0', $this->scale));
$numerator = self::newBigInteger($this->value);
$denominator = self::newBigInteger('1' . \str_repeat('0', $this->scale));
return BigRational::create($numerator, $denominator, false);
return self::newBigRational($numerator, $denominator, false);
}
/**
* {@inheritdoc}
*/
public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
#[Override]
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
{
if ($scale === $this->scale) {
return $this;
@ -722,25 +673,19 @@ final class BigDecimal extends BigNumber
return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode);
}
/**
* {@inheritdoc}
*/
#[Override]
public function toInt() : int
{
return $this->toBigInteger()->toInt();
}
/**
* {@inheritdoc}
*/
#[Override]
public function toFloat() : float
{
return (float) (string) $this;
}
/**
* {@inheritdoc}
*/
#[Override]
public function __toString() : string
{
if ($this->scale === 0) {
@ -772,8 +717,6 @@ final class BigDecimal extends BigNumber
*
* @param array{value: string, scale: int} $data
*
* @return void
*
* @throws \LogicException
*/
public function __unserialize(array $data): void
@ -786,48 +729,9 @@ final class BigDecimal extends BigNumber
$this->scale = $data['scale'];
}
/**
* This method is required by interface Serializable and SHOULD NOT be accessed directly.
*
* @internal
*
* @return string
*/
public function serialize() : string
{
return $this->value . ':' . $this->scale;
}
/**
* This method is only here to implement interface Serializable and cannot be accessed directly.
*
* @internal
* @psalm-suppress RedundantPropertyInitializationCheck
*
* @param string $value
*
* @return void
*
* @throws \LogicException
*/
public function unserialize($value) : void
{
if (isset($this->value)) {
throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
}
[$value, $scale] = \explode(':', $value);
$this->value = $value;
$this->scale = (int) $scale;
}
/**
* Puts the internal values of the given decimal numbers on the same scale.
*
* @param BigDecimal $x The first decimal number.
* @param BigDecimal $y The second decimal number.
*
* @return array{string, string} The scaled integer values of $x and $y.
*/
private function scaleValues(BigDecimal $x, BigDecimal $y) : array
@ -844,11 +748,6 @@ final class BigDecimal extends BigNumber
return [$a, $b];
}
/**
* @param int $scale
*
* @return string
*/
private function valueWithMinScale(int $scale) : string
{
$value = $this->value;
@ -862,8 +761,6 @@ final class BigDecimal extends BigNumber
/**
* Adds leading zeros if necessary to the unscaled value to represent the full decimal number.
*
* @return string
*/
private function getUnscaledValueWithLeadingZeros() : string
{

View file

@ -10,6 +10,7 @@ use Brick\Math\Exception\MathException;
use Brick\Math\Exception\NegativeNumberException;
use Brick\Math\Exception\NumberFormatException;
use Brick\Math\Internal\Calculator;
use Override;
/**
* An arbitrary-size integer.
@ -26,10 +27,8 @@ final class BigInteger extends BigNumber
*
* No leading zeros must be present.
* No leading minus sign must be present if the number is zero.
*
* @var string
*/
private $value;
private readonly string $value;
/**
* Protected constructor. Use a factory method to obtain an instance.
@ -42,19 +41,12 @@ final class BigInteger extends BigNumber
}
/**
* Creates a BigInteger of the given value.
*
* @param BigNumber|int|float|string $value
*
* @return BigInteger
*
* @throws MathException If the value cannot be converted to a BigInteger.
*
* @psalm-pure
*/
public static function of($value) : BigNumber
#[Override]
protected static function from(BigNumber $number): static
{
return parent::of($value)->toBigInteger();
return $number->toBigInteger();
}
/**
@ -71,8 +63,6 @@ final class BigInteger extends BigNumber
* @param string $number The number to convert, in the given base.
* @param int $base The base of the number, between 2 and 36.
*
* @return BigInteger
*
* @throws NumberFormatException If the number is empty, or contains invalid chars for the given base.
* @throws \InvalidArgumentException If the base is out of range.
*
@ -138,8 +128,6 @@ final class BigInteger extends BigNumber
* @param string $number The number to parse.
* @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.
*
* @return BigInteger
*
* @throws NumberFormatException If the given number is empty or contains invalid chars for the given alphabet.
* @throws \InvalidArgumentException If the alphabet does not contain at least 2 chars.
*
@ -183,8 +171,6 @@ final class BigInteger extends BigNumber
* @param bool $signed Whether to interpret as a signed number in two's-complement representation with a leading
* sign bit.
*
* @return BigInteger
*
* @throws NumberFormatException If the string is empty.
*/
public static function fromBytes(string $value, bool $signed = true) : BigInteger
@ -217,15 +203,13 @@ final class BigInteger extends BigNumber
*
* Using the default random bytes generator, this method is suitable for cryptographic use.
*
* @psalm-param callable(int): string $randomBytesGenerator
* @psalm-param (callable(int): string)|null $randomBytesGenerator
*
* @param int $numBits The number of bits.
* @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, and returns a
* string of random bytes of the given length. Defaults to the
* `random_bytes()` function.
*
* @return BigInteger
*
* @throws \InvalidArgumentException If $numBits is negative.
*/
public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null) : BigInteger
@ -239,9 +223,10 @@ final class BigInteger extends BigNumber
}
if ($randomBytesGenerator === null) {
$randomBytesGenerator = 'random_bytes';
$randomBytesGenerator = random_bytes(...);
}
/** @var int<1, max> $byteLength */
$byteLength = \intdiv($numBits - 1, 8) + 1;
$extraBits = ($byteLength * 8 - $numBits);
@ -266,13 +251,14 @@ final class BigInteger extends BigNumber
* and returns a string of random bytes of the given length.
* Defaults to the `random_bytes()` function.
*
* @return BigInteger
*
* @throws MathException If one of the parameters cannot be converted to a BigInteger,
* or `$min` is greater than `$max`.
*/
public static function randomRange($min, $max, ?callable $randomBytesGenerator = null) : BigInteger
{
public static function randomRange(
BigNumber|int|float|string $min,
BigNumber|int|float|string $max,
?callable $randomBytesGenerator = null
) : BigInteger {
$min = BigInteger::of($min);
$max = BigInteger::of($max);
@ -298,8 +284,6 @@ final class BigInteger extends BigNumber
/**
* Returns a BigInteger representing zero.
*
* @return BigInteger
*
* @psalm-pure
*/
public static function zero() : BigInteger
@ -320,8 +304,6 @@ final class BigInteger extends BigNumber
/**
* Returns a BigInteger representing one.
*
* @return BigInteger
*
* @psalm-pure
*/
public static function one() : BigInteger
@ -342,8 +324,6 @@ final class BigInteger extends BigNumber
/**
* Returns a BigInteger representing ten.
*
* @return BigInteger
*
* @psalm-pure
*/
public static function ten() : BigInteger
@ -361,16 +341,29 @@ final class BigInteger extends BigNumber
return $ten;
}
public static function gcdMultiple(BigInteger $a, BigInteger ...$n): BigInteger
{
$result = $a;
foreach ($n as $next) {
$result = $result->gcd($next);
if ($result->isEqualTo(1)) {
return $result;
}
}
return $result;
}
/**
* Returns the sum of this number and the given one.
*
* @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigInteger.
*
* @return BigInteger The result.
*
* @throws MathException If the number is not valid, or is not convertible to a BigInteger.
*/
public function plus($that) : BigInteger
public function plus(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -392,11 +385,9 @@ final class BigInteger extends BigNumber
*
* @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigInteger.
*
* @return BigInteger The result.
*
* @throws MathException If the number is not valid, or is not convertible to a BigInteger.
*/
public function minus($that) : BigInteger
public function minus(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -414,11 +405,9 @@ final class BigInteger extends BigNumber
*
* @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigInteger.
*
* @return BigInteger The result.
*
* @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger.
*/
public function multipliedBy($that) : BigInteger
public function multipliedBy(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -439,14 +428,12 @@ final class BigInteger extends BigNumber
* Returns the result of the division of this number by the given one.
*
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
* @param int $roundingMode An optional rounding mode.
*
* @return BigInteger The result.
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
*
* @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero,
* or RoundingMode::UNNECESSARY is used and the remainder is not zero.
*/
public function dividedBy($that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger
public function dividedBy(BigNumber|int|float|string $that, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigInteger
{
$that = BigInteger::of($that);
@ -466,10 +453,6 @@ final class BigInteger extends BigNumber
/**
* Returns this number exponentiated to the given value.
*
* @param int $exponent The exponent.
*
* @return BigInteger The result.
*
* @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
*/
public function power(int $exponent) : BigInteger
@ -498,11 +481,9 @@ final class BigInteger extends BigNumber
*
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
*
* @return BigInteger
*
* @throws DivisionByZeroException If the divisor is zero.
*/
public function quotient($that) : BigInteger
public function quotient(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -526,11 +507,9 @@ final class BigInteger extends BigNumber
*
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
*
* @return BigInteger
*
* @throws DivisionByZeroException If the divisor is zero.
*/
public function remainder($that) : BigInteger
public function remainder(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -554,9 +533,11 @@ final class BigInteger extends BigNumber
*
* @return BigInteger[] An array containing the quotient and the remainder.
*
* @psalm-return array{BigInteger, BigInteger}
*
* @throws DivisionByZeroException If the divisor is zero.
*/
public function quotientAndRemainder($that) : array
public function quotientAndRemainder(BigNumber|int|float|string $that) : array
{
$that = BigInteger::of($that);
@ -582,11 +563,9 @@ final class BigInteger extends BigNumber
*
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
*
* @return BigInteger
*
* @throws DivisionByZeroException If the divisor is zero.
*/
public function mod($that) : BigInteger
public function mod(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -602,10 +581,6 @@ final class BigInteger extends BigNumber
/**
* Returns the modular multiplicative inverse of this BigInteger modulo $m.
*
* @param BigInteger $m
*
* @return BigInteger
*
* @throws DivisionByZeroException If $m is zero.
* @throws NegativeNumberException If $m is negative.
* @throws MathException If this BigInteger has no multiplicative inverse mod m (that is, this BigInteger
@ -642,12 +617,10 @@ final class BigInteger extends BigNumber
* @param BigNumber|int|float|string $exp The exponent. Must be positive or zero.
* @param BigNumber|int|float|string $mod The modulus. Must be strictly positive.
*
* @return BigInteger
*
* @throws NegativeNumberException If any of the operands is negative.
* @throws DivisionByZeroException If the modulus is zero.
*/
public function modPow($exp, $mod) : BigInteger
public function modPow(BigNumber|int|float|string $exp, BigNumber|int|float|string $mod) : BigInteger
{
$exp = BigInteger::of($exp);
$mod = BigInteger::of($mod);
@ -671,10 +644,8 @@ final class BigInteger extends BigNumber
* The GCD is always positive, unless both operands are zero, in which case it is zero.
*
* @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
*
* @return BigInteger
*/
public function gcd($that) : BigInteger
public function gcd(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -696,8 +667,6 @@ final class BigInteger extends BigNumber
*
* The result is the largest x such that n.
*
* @return BigInteger
*
* @throws NegativeNumberException If this number is negative.
*/
public function sqrt() : BigInteger
@ -713,8 +682,6 @@ final class BigInteger extends BigNumber
/**
* Returns the absolute value of this number.
*
* @return BigInteger
*/
public function abs() : BigInteger
{
@ -723,8 +690,6 @@ final class BigInteger extends BigNumber
/**
* Returns the inverse of this number.
*
* @return BigInteger
*/
public function negated() : BigInteger
{
@ -737,10 +702,8 @@ final class BigInteger extends BigNumber
* This method returns a negative BigInteger if and only if both operands are negative.
*
* @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
*
* @return BigInteger
*/
public function and($that) : BigInteger
public function and(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -753,10 +716,8 @@ final class BigInteger extends BigNumber
* This method returns a negative BigInteger if and only if either of the operands is negative.
*
* @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
*
* @return BigInteger
*/
public function or($that) : BigInteger
public function or(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -769,10 +730,8 @@ final class BigInteger extends BigNumber
* This method returns a negative BigInteger if and only if exactly one of the operands is negative.
*
* @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
*
* @return BigInteger
*/
public function xor($that) : BigInteger
public function xor(BigNumber|int|float|string $that) : BigInteger
{
$that = BigInteger::of($that);
@ -781,8 +740,6 @@ final class BigInteger extends BigNumber
/**
* Returns the bitwise-not of this BigInteger.
*
* @return BigInteger
*/
public function not() : BigInteger
{
@ -791,10 +748,6 @@ final class BigInteger extends BigNumber
/**
* Returns the integer left shifted by a given number of bits.
*
* @param int $distance The distance to shift.
*
* @return BigInteger
*/
public function shiftedLeft(int $distance) : BigInteger
{
@ -811,10 +764,6 @@ final class BigInteger extends BigNumber
/**
* Returns the integer right shifted by a given number of bits.
*
* @param int $distance The distance to shift.
*
* @return BigInteger
*/
public function shiftedRight(int $distance) : BigInteger
{
@ -840,8 +789,6 @@ final class BigInteger extends BigNumber
*
* For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation.
* Computes (ceil(log2(this < 0 ? -this : this+1))).
*
* @return int
*/
public function getBitLength() : int
{
@ -860,8 +807,6 @@ final class BigInteger extends BigNumber
* Returns the index of the rightmost (lowest-order) one bit in this BigInteger.
*
* Returns -1 if this BigInteger contains no one bits.
*
* @return int
*/
public function getLowestSetBit() : int
{
@ -881,8 +826,6 @@ final class BigInteger extends BigNumber
/**
* Returns whether this number is even.
*
* @return bool
*/
public function isEven() : bool
{
@ -891,8 +834,6 @@ final class BigInteger extends BigNumber
/**
* Returns whether this number is odd.
*
* @return bool
*/
public function isOdd() : bool
{
@ -906,8 +847,6 @@ final class BigInteger extends BigNumber
*
* @param int $n The bit to test, 0-based.
*
* @return bool
*
* @throws \InvalidArgumentException If the bit to test is negative.
*/
public function testBit(int $n) : bool
@ -919,10 +858,8 @@ final class BigInteger extends BigNumber
return $this->shiftedRight($n)->isOdd();
}
/**
* {@inheritdoc}
*/
public function compareTo($that) : int
#[Override]
public function compareTo(BigNumber|int|float|string $that) : int
{
$that = BigNumber::of($that);
@ -933,49 +870,37 @@ final class BigInteger extends BigNumber
return - $that->compareTo($this);
}
/**
* {@inheritdoc}
*/
#[Override]
public function getSign() : int
{
return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBigInteger() : BigInteger
{
return $this;
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBigDecimal() : BigDecimal
{
return BigDecimal::create($this->value);
return self::newBigDecimal($this->value);
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBigRational() : BigRational
{
return BigRational::create($this, BigInteger::one(), false);
return self::newBigRational($this, BigInteger::one(), false);
}
/**
* {@inheritdoc}
*/
public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
#[Override]
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
{
return $this->toBigDecimal()->toScale($scale, $roundingMode);
}
/**
* {@inheritdoc}
*/
#[Override]
public function toInt() : int
{
$intValue = (int) $this->value;
@ -987,9 +912,7 @@ final class BigInteger extends BigNumber
return $intValue;
}
/**
* {@inheritdoc}
*/
#[Override]
public function toFloat() : float
{
return (float) $this->value;
@ -1000,10 +923,6 @@ final class BigInteger extends BigNumber
*
* The output will always be lowercase for bases greater than 10.
*
* @param int $base
*
* @return string
*
* @throws \InvalidArgumentException If the base is out of range.
*/
public function toBase(int $base) : string
@ -1027,8 +946,6 @@ final class BigInteger extends BigNumber
*
* @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.
*
* @return string
*
* @throws NegativeNumberException If this number is negative.
* @throws \InvalidArgumentException If the given alphabet does not contain at least 2 chars.
*/
@ -1063,8 +980,6 @@ final class BigInteger extends BigNumber
*
* @param bool $signed Whether to output a signed number in two's-complement representation with a leading sign bit.
*
* @return string
*
* @throws NegativeNumberException If $signed is false, and the number is negative.
*/
public function toBytes(bool $signed = true) : string
@ -1108,9 +1023,7 @@ final class BigInteger extends BigNumber
return \hex2bin($hex);
}
/**
* {@inheritdoc}
*/
#[Override]
public function __toString() : string
{
return $this->value;
@ -1136,8 +1049,6 @@ final class BigInteger extends BigNumber
*
* @param array{value: string} $data
*
* @return void
*
* @throws \LogicException
*/
public function __unserialize(array $data): void
@ -1148,37 +1059,4 @@ final class BigInteger extends BigNumber
$this->value = $data['value'];
}
/**
* This method is required by interface Serializable and SHOULD NOT be accessed directly.
*
* @internal
*
* @return string
*/
public function serialize() : string
{
return $this->value;
}
/**
* This method is only here to implement interface Serializable and cannot be accessed directly.
*
* @internal
* @psalm-suppress RedundantPropertyInitializationCheck
*
* @param string $value
*
* @return void
*
* @throws \LogicException
*/
public function unserialize($value) : void
{
if (isset($this->value)) {
throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
}
$this->value = $value;
}
}

View file

@ -8,32 +8,36 @@ use Brick\Math\Exception\DivisionByZeroException;
use Brick\Math\Exception\MathException;
use Brick\Math\Exception\NumberFormatException;
use Brick\Math\Exception\RoundingNecessaryException;
use Override;
/**
* Common interface for arbitrary-precision rational numbers.
*
* @psalm-immutable
*/
abstract class BigNumber implements \Serializable, \JsonSerializable
abstract class BigNumber implements \JsonSerializable
{
/**
* The regular expression used to parse integer, decimal and rational numbers.
* The regular expression used to parse integer or decimal numbers.
*/
private const PARSE_REGEXP =
private const PARSE_REGEXP_NUMERICAL =
'/^' .
'(?<sign>[\-\+])?' .
'(?:' .
'(?:' .
'(?<integral>[0-9]+)?' .
'(?<point>\.)?' .
'(?<fractional>[0-9]+)?' .
'(?:[eE](?<exponent>[\-\+]?[0-9]+))?' .
')|(?:' .
'$/';
/**
* The regular expression used to parse rational numbers.
*/
private const PARSE_REGEXP_RATIONAL =
'/^' .
'(?<sign>[\-\+])?' .
'(?<numerator>[0-9]+)' .
'\/?' .
'(?<denominator>[0-9]+)' .
')' .
')' .
'$/';
/**
@ -48,16 +52,33 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
* - strings containing a `.` character or using an exponential notation are returned as BigDecimal
* - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger
*
* @param BigNumber|int|float|string $value
*
* @return BigNumber
* @throws NumberFormatException If the format of the number is not valid.
* @throws DivisionByZeroException If the value represents a rational number with a denominator of zero.
* @throws RoundingNecessaryException If the value cannot be converted to an instance of the subclass without rounding.
*
* @psalm-pure
*/
final public static function of(BigNumber|int|float|string $value) : static
{
$value = self::_of($value);
if (static::class === BigNumber::class) {
// https://github.com/vimeo/psalm/issues/10309
assert($value instanceof static);
return $value;
}
return static::from($value);
}
/**
* @throws NumberFormatException If the format of the number is not valid.
* @throws DivisionByZeroException If the value represents a rational number with a denominator of zero.
*
* @psalm-pure
*/
public static function of($value) : BigNumber
private static function _of(BigNumber|int|float|string $value) : BigNumber
{
if ($value instanceof BigNumber) {
return $value;
@ -67,37 +88,25 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
return new BigInteger((string) $value);
}
/** @psalm-suppress RedundantCastGivenDocblockType We cannot trust the untyped $value here! */
$value = \is_float($value) ? self::floatToString($value) : (string) $value;
$throw = static function() use ($value) : void {
throw new NumberFormatException(\sprintf(
'The given value "%s" does not represent a valid number.',
$value
));
};
if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) {
$throw();
if (is_float($value)) {
$value = (string) $value;
}
$getMatch = static function(string $value) use ($matches) : ?string {
return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null;
};
if (str_contains($value, '/')) {
// Rational number
if (\preg_match(self::PARSE_REGEXP_RATIONAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) {
throw NumberFormatException::invalidFormat($value);
}
$sign = $getMatch('sign');
$numerator = $getMatch('numerator');
$denominator = $getMatch('denominator');
$sign = $matches['sign'];
$numerator = $matches['numerator'];
$denominator = $matches['denominator'];
if ($numerator !== null) {
assert($numerator !== null);
assert($denominator !== null);
if ($sign !== null) {
$numerator = $sign . $numerator;
}
$numerator = self::cleanUp($numerator);
$denominator = self::cleanUp($denominator);
$numerator = self::cleanUp($sign, $numerator);
$denominator = self::cleanUp(null, $denominator);
if ($denominator === '0') {
throw DivisionByZeroException::denominatorMustNotBeZero();
@ -108,15 +117,20 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
new BigInteger($denominator),
false
);
} else {
// Integer or decimal number
if (\preg_match(self::PARSE_REGEXP_NUMERICAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) {
throw NumberFormatException::invalidFormat($value);
}
$point = $getMatch('point');
$integral = $getMatch('integral');
$fractional = $getMatch('fractional');
$exponent = $getMatch('exponent');
$sign = $matches['sign'];
$point = $matches['point'];
$integral = $matches['integral'];
$fractional = $matches['fractional'];
$exponent = $matches['exponent'];
if ($integral === null && $fractional === null) {
$throw();
throw NumberFormatException::invalidFormat($value);
}
if ($integral === null) {
@ -131,7 +145,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
throw new NumberFormatException('Exponent too large.');
}
$unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional);
$unscaledValue = self::cleanUp($sign, $integral . $fractional);
$scale = \strlen($fractional) - $exponent;
@ -145,51 +159,52 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
return new BigDecimal($unscaledValue, $scale);
}
$integral = self::cleanUp(($sign ?? '') . $integral);
$integral = self::cleanUp($sign, $integral);
return new BigInteger($integral);
}
/**
* Safely converts float to string, avoiding locale-dependent issues.
*
* @see https://github.com/brick/math/pull/20
*
* @param float $float
*
* @return string
*
* @psalm-pure
* @psalm-suppress ImpureFunctionCall
*/
private static function floatToString(float $float) : string
{
$currentLocale = \setlocale(LC_NUMERIC, '0');
\setlocale(LC_NUMERIC, 'C');
$result = (string) $float;
\setlocale(LC_NUMERIC, $currentLocale);
return $result;
}
/**
* Proxy method to access protected constructors from sibling classes.
* Overridden by subclasses to convert a BigNumber to an instance of the subclass.
*
* @internal
*
* @param mixed ...$args The arguments to the constructor.
*
* @return static
* @throws RoundingNecessaryException If the value cannot be converted.
*
* @psalm-pure
* @psalm-suppress TooManyArguments
* @psalm-suppress UnsafeInstantiation
*/
protected static function create(... $args) : BigNumber
abstract protected static function from(BigNumber $number): static;
/**
* Proxy method to access BigInteger's protected constructor from sibling classes.
*
* @internal
* @psalm-pure
*/
final protected function newBigInteger(string $value) : BigInteger
{
return new static(... $args);
return new BigInteger($value);
}
/**
* Proxy method to access BigDecimal's protected constructor from sibling classes.
*
* @internal
* @psalm-pure
*/
final protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal
{
return new BigDecimal($value, $scale);
}
/**
* Proxy method to access BigRational's protected constructor from sibling classes.
*
* @internal
* @psalm-pure
*/
final protected function newBigRational(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) : BigRational
{
return new BigRational($numerator, $denominator, $checkDenominator);
}
/**
@ -198,16 +213,12 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
* @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
* to an instance of the class this method is called on.
*
* @return static The minimum value.
*
* @throws \InvalidArgumentException If no values are given.
* @throws MathException If an argument is not valid.
*
* @psalm-suppress LessSpecificReturnStatement
* @psalm-suppress MoreSpecificReturnType
* @psalm-pure
*/
public static function min(...$values) : BigNumber
final public static function min(BigNumber|int|float|string ...$values) : static
{
$min = null;
@ -232,16 +243,12 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
* @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
* to an instance of the class this method is called on.
*
* @return static The maximum value.
*
* @throws \InvalidArgumentException If no values are given.
* @throws MathException If an argument is not valid.
*
* @psalm-suppress LessSpecificReturnStatement
* @psalm-suppress MoreSpecificReturnType
* @psalm-pure
*/
public static function max(...$values) : BigNumber
final public static function max(BigNumber|int|float|string ...$values) : static
{
$max = null;
@ -266,18 +273,14 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
* @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible
* to an instance of the class this method is called on.
*
* @return static The sum.
*
* @throws \InvalidArgumentException If no values are given.
* @throws MathException If an argument is not valid.
*
* @psalm-suppress LessSpecificReturnStatement
* @psalm-suppress MoreSpecificReturnType
* @psalm-pure
*/
public static function sum(...$values) : BigNumber
final public static function sum(BigNumber|int|float|string ...$values) : static
{
/** @var BigNumber|null $sum */
/** @var static|null $sum */
$sum = null;
foreach ($values as $value) {
@ -301,11 +304,6 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
* depending on their ability to perform the operation. This will also require a version bump because we're
* potentially breaking custom BigNumber implementations (if any...)
*
* @param BigNumber $a
* @param BigNumber $b
*
* @return BigNumber
*
* @psalm-pure
*/
private static function add(BigNumber $a, BigNumber $b) : BigNumber
@ -332,141 +330,100 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
}
/**
* Removes optional leading zeros and + sign from the given number.
* Removes optional leading zeros and applies sign.
*
* @param string $number The number, validated as a non-empty string of digits with optional leading sign.
*
* @return string
* @param string|null $sign The sign, '+' or '-', optional. Null is allowed for convenience and treated as '+'.
* @param string $number The number, validated as a non-empty string of digits.
*
* @psalm-pure
*/
private static function cleanUp(string $number) : string
private static function cleanUp(string|null $sign, string $number) : string
{
$firstChar = $number[0];
if ($firstChar === '+' || $firstChar === '-') {
$number = \substr($number, 1);
}
$number = \ltrim($number, '0');
if ($number === '') {
return '0';
}
if ($firstChar === '-') {
return '-' . $number;
}
return $number;
return $sign === '-' ? '-' . $number : $number;
}
/**
* Checks if this number is equal to the given one.
*
* @param BigNumber|int|float|string $that
*
* @return bool
*/
public function isEqualTo($that) : bool
final public function isEqualTo(BigNumber|int|float|string $that) : bool
{
return $this->compareTo($that) === 0;
}
/**
* Checks if this number is strictly lower than the given one.
*
* @param BigNumber|int|float|string $that
*
* @return bool
*/
public function isLessThan($that) : bool
final public function isLessThan(BigNumber|int|float|string $that) : bool
{
return $this->compareTo($that) < 0;
}
/**
* Checks if this number is lower than or equal to the given one.
*
* @param BigNumber|int|float|string $that
*
* @return bool
*/
public function isLessThanOrEqualTo($that) : bool
final public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool
{
return $this->compareTo($that) <= 0;
}
/**
* Checks if this number is strictly greater than the given one.
*
* @param BigNumber|int|float|string $that
*
* @return bool
*/
public function isGreaterThan($that) : bool
final public function isGreaterThan(BigNumber|int|float|string $that) : bool
{
return $this->compareTo($that) > 0;
}
/**
* Checks if this number is greater than or equal to the given one.
*
* @param BigNumber|int|float|string $that
*
* @return bool
*/
public function isGreaterThanOrEqualTo($that) : bool
final public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool
{
return $this->compareTo($that) >= 0;
}
/**
* Checks if this number equals zero.
*
* @return bool
*/
public function isZero() : bool
final public function isZero() : bool
{
return $this->getSign() === 0;
}
/**
* Checks if this number is strictly negative.
*
* @return bool
*/
public function isNegative() : bool
final public function isNegative() : bool
{
return $this->getSign() < 0;
}
/**
* Checks if this number is negative or zero.
*
* @return bool
*/
public function isNegativeOrZero() : bool
final public function isNegativeOrZero() : bool
{
return $this->getSign() <= 0;
}
/**
* Checks if this number is strictly positive.
*
* @return bool
*/
public function isPositive() : bool
final public function isPositive() : bool
{
return $this->getSign() > 0;
}
/**
* Checks if this number is positive or zero.
*
* @return bool
*/
public function isPositiveOrZero() : bool
final public function isPositiveOrZero() : bool
{
return $this->getSign() >= 0;
}
@ -474,6 +431,8 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
/**
* Returns the sign of this number.
*
* @psalm-return -1|0|1
*
* @return int -1 if the number is negative, 0 if zero, 1 if positive.
*/
abstract public function getSign() : int;
@ -481,19 +440,17 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
/**
* Compares this number to the given one.
*
* @param BigNumber|int|float|string $that
* @psalm-return -1|0|1
*
* @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`.
* @return int -1 if `$this` is lower than, 0 if equal to, 1 if greater than `$that`.
*
* @throws MathException If the number is not valid.
*/
abstract public function compareTo($that) : int;
abstract public function compareTo(BigNumber|int|float|string $that) : int;
/**
* Converts this number to a BigInteger.
*
* @return BigInteger The converted number.
*
* @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding.
*/
abstract public function toBigInteger() : BigInteger;
@ -501,16 +458,12 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
/**
* Converts this number to a BigDecimal.
*
* @return BigDecimal The converted number.
*
* @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding.
*/
abstract public function toBigDecimal() : BigDecimal;
/**
* Converts this number to a BigRational.
*
* @return BigRational The converted number.
*/
abstract public function toBigRational() : BigRational;
@ -518,14 +471,12 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
* Converts this number to a BigDecimal with the given scale, using rounding if necessary.
*
* @param int $scale The scale of the resulting `BigDecimal`.
* @param int $roundingMode A `RoundingMode` constant.
*
* @return BigDecimal
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
*
* @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding.
* This only applies when RoundingMode::UNNECESSARY is used.
*/
abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;
abstract public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;
/**
* Returns the exact value of this number as a native integer.
@ -533,8 +484,6 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
* If this number cannot be converted to a native integer without losing precision, an exception is thrown.
* Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit.
*
* @return int The converted value.
*
* @throws MathException If this number cannot be exactly converted to a native integer.
*/
abstract public function toInt() : int;
@ -547,8 +496,6 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
*
* If the number is greater than the largest representable floating point number, positive infinity is returned.
* If the number is less than the smallest representable floating point number, negative infinity is returned.
*
* @return float The converted value.
*/
abstract public function toFloat() : float;
@ -557,15 +504,11 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
*
* The output of this method can be parsed by the `of()` factory method;
* this will yield an object equal to this one, without any information loss.
*
* @return string
*/
abstract public function __toString() : string;
/**
* {@inheritdoc}
*/
public function jsonSerialize() : string
#[Override]
final public function jsonSerialize() : string
{
return $this->__toString();
}

View file

@ -8,6 +8,7 @@ use Brick\Math\Exception\DivisionByZeroException;
use Brick\Math\Exception\MathException;
use Brick\Math\Exception\NumberFormatException;
use Brick\Math\Exception\RoundingNecessaryException;
use Override;
/**
* An arbitrarily large rational number.
@ -20,17 +21,13 @@ final class BigRational extends BigNumber
{
/**
* The numerator.
*
* @var BigInteger
*/
private $numerator;
private readonly BigInteger $numerator;
/**
* The denominator. Always strictly positive.
*
* @var BigInteger
*/
private $denominator;
private readonly BigInteger $denominator;
/**
* Protected constructor. Use a factory method to obtain an instance.
@ -59,19 +56,12 @@ final class BigRational extends BigNumber
}
/**
* Creates a BigRational of the given value.
*
* @param BigNumber|int|float|string $value
*
* @return BigRational
*
* @throws MathException If the value cannot be converted to a BigRational.
*
* @psalm-pure
*/
public static function of($value) : BigNumber
#[Override]
protected static function from(BigNumber $number): static
{
return parent::of($value)->toBigRational();
return $number->toBigRational();
}
/**
@ -83,16 +73,16 @@ final class BigRational extends BigNumber
* @param BigNumber|int|float|string $numerator The numerator. Must be convertible to a BigInteger.
* @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger.
*
* @return BigRational
*
* @throws NumberFormatException If an argument does not represent a valid number.
* @throws RoundingNecessaryException If an argument represents a non-integer number.
* @throws DivisionByZeroException If the denominator is zero.
*
* @psalm-pure
*/
public static function nd($numerator, $denominator) : BigRational
{
public static function nd(
BigNumber|int|float|string $numerator,
BigNumber|int|float|string $denominator,
) : BigRational {
$numerator = BigInteger::of($numerator);
$denominator = BigInteger::of($denominator);
@ -102,8 +92,6 @@ final class BigRational extends BigNumber
/**
* Returns a BigRational representing zero.
*
* @return BigRational
*
* @psalm-pure
*/
public static function zero() : BigRational
@ -124,8 +112,6 @@ final class BigRational extends BigNumber
/**
* Returns a BigRational representing one.
*
* @return BigRational
*
* @psalm-pure
*/
public static function one() : BigRational
@ -146,8 +132,6 @@ final class BigRational extends BigNumber
/**
* Returns a BigRational representing ten.
*
* @return BigRational
*
* @psalm-pure
*/
public static function ten() : BigRational
@ -165,17 +149,11 @@ final class BigRational extends BigNumber
return $ten;
}
/**
* @return BigInteger
*/
public function getNumerator() : BigInteger
{
return $this->numerator;
}
/**
* @return BigInteger
*/
public function getDenominator() : BigInteger
{
return $this->denominator;
@ -183,8 +161,6 @@ final class BigRational extends BigNumber
/**
* Returns the quotient of the division of the numerator by the denominator.
*
* @return BigInteger
*/
public function quotient() : BigInteger
{
@ -193,8 +169,6 @@ final class BigRational extends BigNumber
/**
* Returns the remainder of the division of the numerator by the denominator.
*
* @return BigInteger
*/
public function remainder() : BigInteger
{
@ -205,6 +179,8 @@ final class BigRational extends BigNumber
* Returns the quotient and remainder of the division of the numerator by the denominator.
*
* @return BigInteger[]
*
* @psalm-return array{BigInteger, BigInteger}
*/
public function quotientAndRemainder() : array
{
@ -216,11 +192,9 @@ final class BigRational extends BigNumber
*
* @param BigNumber|int|float|string $that The number to add.
*
* @return BigRational The result.
*
* @throws MathException If the number is not valid.
*/
public function plus($that) : BigRational
public function plus(BigNumber|int|float|string $that) : BigRational
{
$that = BigRational::of($that);
@ -236,11 +210,9 @@ final class BigRational extends BigNumber
*
* @param BigNumber|int|float|string $that The number to subtract.
*
* @return BigRational The result.
*
* @throws MathException If the number is not valid.
*/
public function minus($that) : BigRational
public function minus(BigNumber|int|float|string $that) : BigRational
{
$that = BigRational::of($that);
@ -256,11 +228,9 @@ final class BigRational extends BigNumber
*
* @param BigNumber|int|float|string $that The multiplier.
*
* @return BigRational The result.
*
* @throws MathException If the multiplier is not a valid number.
*/
public function multipliedBy($that) : BigRational
public function multipliedBy(BigNumber|int|float|string $that) : BigRational
{
$that = BigRational::of($that);
@ -275,11 +245,9 @@ final class BigRational extends BigNumber
*
* @param BigNumber|int|float|string $that The divisor.
*
* @return BigRational The result.
*
* @throws MathException If the divisor is not a valid number, or is zero.
*/
public function dividedBy($that) : BigRational
public function dividedBy(BigNumber|int|float|string $that) : BigRational
{
$that = BigRational::of($that);
@ -292,10 +260,6 @@ final class BigRational extends BigNumber
/**
* Returns this number exponentiated to the given value.
*
* @param int $exponent The exponent.
*
* @return BigRational The result.
*
* @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
*/
public function power(int $exponent) : BigRational
@ -322,8 +286,6 @@ final class BigRational extends BigNumber
*
* The reciprocal has the numerator and denominator swapped.
*
* @return BigRational
*
* @throws DivisionByZeroException If the numerator is zero.
*/
public function reciprocal() : BigRational
@ -333,8 +295,6 @@ final class BigRational extends BigNumber
/**
* Returns the absolute value of this BigRational.
*
* @return BigRational
*/
public function abs() : BigRational
{
@ -343,8 +303,6 @@ final class BigRational extends BigNumber
/**
* Returns the negated value of this BigRational.
*
* @return BigRational
*/
public function negated() : BigRational
{
@ -353,8 +311,6 @@ final class BigRational extends BigNumber
/**
* Returns the simplified value of this BigRational.
*
* @return BigRational
*/
public function simplified() : BigRational
{
@ -366,25 +322,19 @@ final class BigRational extends BigNumber
return new BigRational($numerator, $denominator, false);
}
/**
* {@inheritdoc}
*/
public function compareTo($that) : int
#[Override]
public function compareTo(BigNumber|int|float|string $that) : int
{
return $this->minus($that)->getSign();
}
/**
* {@inheritdoc}
*/
#[Override]
public function getSign() : int
{
return $this->numerator->getSign();
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBigInteger() : BigInteger
{
$simplified = $this->simplified();
@ -396,49 +346,38 @@ final class BigRational extends BigNumber
return $simplified->numerator;
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBigDecimal() : BigDecimal
{
return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator);
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBigRational() : BigRational
{
return $this;
}
/**
* {@inheritdoc}
*/
public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
#[Override]
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
{
return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);
}
/**
* {@inheritdoc}
*/
#[Override]
public function toInt() : int
{
return $this->toBigInteger()->toInt();
}
/**
* {@inheritdoc}
*/
#[Override]
public function toFloat() : float
{
return $this->numerator->toFloat() / $this->denominator->toFloat();
$simplified = $this->simplified();
return $simplified->numerator->toFloat() / $simplified->denominator->toFloat();
}
/**
* {@inheritdoc}
*/
#[Override]
public function __toString() : string
{
$numerator = (string) $this->numerator;
@ -448,7 +387,7 @@ final class BigRational extends BigNumber
return $numerator;
}
return $this->numerator . '/' . $this->denominator;
return $numerator . '/' . $denominator;
}
/**
@ -471,8 +410,6 @@ final class BigRational extends BigNumber
*
* @param array{numerator: BigInteger, denominator: BigInteger} $data
*
* @return void
*
* @throws \LogicException
*/
public function __unserialize(array $data): void
@ -484,40 +421,4 @@ final class BigRational extends BigNumber
$this->numerator = $data['numerator'];
$this->denominator = $data['denominator'];
}
/**
* This method is required by interface Serializable and SHOULD NOT be accessed directly.
*
* @internal
*
* @return string
*/
public function serialize() : string
{
return $this->numerator . '/' . $this->denominator;
}
/**
* This method is only here to implement interface Serializable and cannot be accessed directly.
*
* @internal
* @psalm-suppress RedundantPropertyInitializationCheck
*
* @param string $value
*
* @return void
*
* @throws \LogicException
*/
public function unserialize($value) : void
{
if (isset($this->numerator)) {
throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
}
[$numerator, $denominator] = \explode('/', $value);
$this->numerator = BigInteger::of($numerator);
$this->denominator = BigInteger::of($denominator);
}
}

View file

@ -10,8 +10,6 @@ namespace Brick\Math\Exception;
class DivisionByZeroException extends MathException
{
/**
* @return DivisionByZeroException
*
* @psalm-pure
*/
public static function divisionByZero() : DivisionByZeroException
@ -20,8 +18,6 @@ class DivisionByZeroException extends MathException
}
/**
* @return DivisionByZeroException
*
* @psalm-pure
*/
public static function modulusMustNotBeZero() : DivisionByZeroException
@ -30,8 +26,6 @@ class DivisionByZeroException extends MathException
}
/**
* @return DivisionByZeroException
*
* @psalm-pure
*/
public static function denominatorMustNotBeZero() : DivisionByZeroException

View file

@ -12,10 +12,6 @@ use Brick\Math\BigInteger;
class IntegerOverflowException extends MathException
{
/**
* @param BigInteger $value
*
* @return IntegerOverflowException
*
* @psalm-pure
*/
public static function toIntOverflow(BigInteger $value) : IntegerOverflowException

View file

@ -6,9 +6,7 @@ namespace Brick\Math\Exception;
/**
* Base class for all math exceptions.
*
* This class is abstract to ensure that only fine-grained exceptions are thrown throughout the code.
*/
class MathException extends \RuntimeException
class MathException extends \Exception
{
}

View file

@ -9,11 +9,17 @@ namespace Brick\Math\Exception;
*/
class NumberFormatException extends MathException
{
public static function invalidFormat(string $value) : self
{
return new self(\sprintf(
'The given value "%s" does not represent a valid number.',
$value,
));
}
/**
* @param string $char The failing character.
*
* @return NumberFormatException
*
* @psalm-pure
*/
public static function charNotInAlphabet(string $char) : self
@ -30,6 +36,6 @@ class NumberFormatException extends MathException
$char = '"' . $char . '"';
}
return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char));
return new self(\sprintf('Char %s is not a valid character in the given alphabet.', $char));
}
}

View file

@ -10,8 +10,6 @@ namespace Brick\Math\Exception;
class RoundingNecessaryException extends MathException
{
/**
* @return RoundingNecessaryException
*
* @psalm-pure
*/
public static function roundingNecessary() : RoundingNecessaryException

View file

@ -25,7 +25,7 @@ abstract class Calculator
/**
* The maximum exponent value allowed for the pow() method.
*/
public const MAX_POWER = 1000000;
public const MAX_POWER = 1_000_000;
/**
* The alphabet for converting from and to base 2 to 36, lowercase.
@ -34,10 +34,8 @@ abstract class Calculator
/**
* The Calculator instance in use.
*
* @var Calculator|null
*/
private static $instance;
private static ?Calculator $instance = null;
/**
* Sets the Calculator instance to use.
@ -45,8 +43,6 @@ abstract class Calculator
* An instance is typically set only in unit tests: the autodetect is usually the best option.
*
* @param Calculator|null $calculator The calculator instance, or NULL to revert to autodetect.
*
* @return void
*/
final public static function set(?Calculator $calculator) : void
{
@ -58,8 +54,6 @@ abstract class Calculator
*
* If none has been explicitly set, the fastest available implementation will be returned.
*
* @return Calculator
*
* @psalm-pure
* @psalm-suppress ImpureStaticProperty
*/
@ -77,8 +71,6 @@ abstract class Calculator
* Returns the fastest available Calculator implementation.
*
* @codeCoverageIgnore
*
* @return Calculator
*/
private static function detect() : Calculator
{
@ -96,9 +88,6 @@ abstract class Calculator
/**
* Extracts the sign & digits of the operands.
*
* @param string $a The first operand.
* @param string $b The second operand.
*
* @return array{bool, bool, string, string} Whether $a and $b are negative, followed by their digits.
*/
final protected function init(string $a, string $b) : array
@ -114,10 +103,6 @@ abstract class Calculator
/**
* Returns the absolute value of a number.
*
* @param string $n The number.
*
* @return string The absolute value.
*/
final public function abs(string $n) : string
{
@ -126,10 +111,6 @@ abstract class Calculator
/**
* Negates a number.
*
* @param string $n The number.
*
* @return string The negated value.
*/
final public function neg(string $n) : string
{
@ -147,10 +128,9 @@ abstract class Calculator
/**
* Compares two numbers.
*
* @param string $a The first number.
* @param string $b The second number.
* @psalm-return -1|0|1
*
* @return int [-1, 0, 1] If the first number is less than, equal to, or greater than the second number.
* @return int -1 if the first number is less than, 0 if equal to, 1 if greater than the second number.
*/
final public function cmp(string $a, string $b) : int
{
@ -180,31 +160,16 @@ abstract class Calculator
/**
* Adds two numbers.
*
* @param string $a The augend.
* @param string $b The addend.
*
* @return string The sum.
*/
abstract public function add(string $a, string $b) : string;
/**
* Subtracts two numbers.
*
* @param string $a The minuend.
* @param string $b The subtrahend.
*
* @return string The difference.
*/
abstract public function sub(string $a, string $b) : string;
/**
* Multiplies two numbers.
*
* @param string $a The multiplicand.
* @param string $b The multiplier.
*
* @return string The product.
*/
abstract public function mul(string $a, string $b) : string;
@ -234,7 +199,7 @@ abstract class Calculator
* @param string $a The dividend.
* @param string $b The divisor, must not be zero.
*
* @return string[] An array containing the quotient and remainder.
* @return array{string, string} An array containing the quotient and remainder.
*/
abstract public function divQR(string $a, string $b) : array;
@ -249,10 +214,7 @@ abstract class Calculator
abstract public function pow(string $a, int $e) : string;
/**
* @param string $a
* @param string $b The modulus; must not be zero.
*
* @return string
*/
public function mod(string $a, string $b) : string
{
@ -266,10 +228,7 @@ abstract class Calculator
*
* This method can be overridden by the concrete implementation if the underlying library has built-in support.
*
* @param string $x
* @param string $m The modulus; must not be negative or zero.
*
* @return string|null
*/
public function modInverse(string $x, string $m) : ?string
{
@ -283,9 +242,7 @@ abstract class Calculator
$modVal = $this->mod($x, $m);
}
$x = '0';
$y = '0';
$g = $this->gcdExtended($modVal, $m, $x, $y);
[$g, $x] = $this->gcdExtended($modVal, $m);
if ($g !== '1') {
return null;
@ -300,8 +257,6 @@ abstract class Calculator
* @param string $base The base number; must be positive or zero.
* @param string $exp The exponent; must be positive or zero.
* @param string $mod The modulus; must be strictly positive.
*
* @return string The power.
*/
abstract public function modPow(string $base, string $exp, string $mod) : string;
@ -311,9 +266,6 @@ abstract class Calculator
* This method can be overridden by the concrete implementation if the underlying library
* has built-in support for GCD calculations.
*
* @param string $a The first number.
* @param string $b The second number.
*
* @return string The GCD, always positive, or zero if both arguments are zero.
*/
public function gcd(string $a, string $b) : string
@ -329,24 +281,21 @@ abstract class Calculator
return $this->gcd($b, $this->divR($a, $b));
}
private function gcdExtended(string $a, string $b, string &$x, string &$y) : string
/**
* @return array{string, string, string} GCD, X, Y
*/
private function gcdExtended(string $a, string $b) : array
{
if ($a === '0') {
$x = '0';
$y = '1';
return $b;
return [$b, '0', '1'];
}
$x1 = '0';
$y1 = '0';
$gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1);
[$gcd, $x1, $y1] = $this->gcdExtended($this->mod($b, $a), $a);
$x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1));
$y = $x1;
return $gcd;
return [$gcd, $x, $y];
}
/**
@ -354,10 +303,6 @@ abstract class Calculator
*
* The result is the largest x such that n.
* The input MUST NOT be negative.
*
* @param string $n The number.
*
* @return string The square root.
*/
abstract public function sqrt(string $n) : string;
@ -487,14 +432,14 @@ abstract class Calculator
*
* @param string $a The dividend.
* @param string $b The divisor, must not be zero.
* @param int $roundingMode The rounding mode.
*
* @return string
* @param RoundingMode $roundingMode The rounding mode.
*
* @throws \InvalidArgumentException If the rounding mode is invalid.
* @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary.
*
* @psalm-suppress ImpureFunctionCall
*/
final public function divRound(string $a, string $b, int $roundingMode) : string
final public function divRound(string $a, string $b, RoundingMode $roundingMode) : string
{
[$quotient, $remainder] = $this->divQR($a, $b);
@ -570,11 +515,6 @@ abstract class Calculator
*
* This method can be overridden by the concrete implementation if the underlying library
* has built-in support for bitwise operations.
*
* @param string $a
* @param string $b
*
* @return string
*/
public function and(string $a, string $b) : string
{
@ -586,11 +526,6 @@ abstract class Calculator
*
* This method can be overridden by the concrete implementation if the underlying library
* has built-in support for bitwise operations.
*
* @param string $a
* @param string $b
*
* @return string
*/
public function or(string $a, string $b) : string
{
@ -602,11 +537,6 @@ abstract class Calculator
*
* This method can be overridden by the concrete implementation if the underlying library
* has built-in support for bitwise operations.
*
* @param string $a
* @param string $b
*
* @return string
*/
public function xor(string $a, string $b) : string
{
@ -616,11 +546,9 @@ abstract class Calculator
/**
* Performs a bitwise operation on a decimal number.
*
* @param string $operator The operator to use, must be "and", "or" or "xor".
* @param 'and'|'or'|'xor' $operator The operator to use.
* @param string $a The left operand.
* @param string $b The right operand.
*
* @return string
*/
private function bitwise(string $operator, string $a, string $b) : string
{
@ -645,27 +573,17 @@ abstract class Calculator
$bBin = $this->twosComplement($bBin);
}
switch ($operator) {
case 'and':
$value = $aBin & $bBin;
$negative = ($aNeg and $bNeg);
break;
$value = match ($operator) {
'and' => $aBin & $bBin,
'or' => $aBin | $bBin,
'xor' => $aBin ^ $bBin,
};
case 'or':
$value = $aBin | $bBin;
$negative = ($aNeg or $bNeg);
break;
case 'xor':
$value = $aBin ^ $bBin;
$negative = ($aNeg xor $bNeg);
break;
// @codeCoverageIgnoreStart
default:
throw new \InvalidArgumentException('Invalid bitwise operator.');
// @codeCoverageIgnoreEnd
}
$negative = match ($operator) {
'and' => $aNeg and $bNeg,
'or' => $aNeg or $bNeg,
'xor' => $aNeg xor $bNeg,
};
if ($negative) {
$value = $this->twosComplement($value);
@ -678,8 +596,6 @@ abstract class Calculator
/**
* @param string $number A positive, binary number.
*
* @return string
*/
private function twosComplement(string $number) : string
{
@ -709,8 +625,6 @@ abstract class Calculator
* Converts a decimal number to a binary string.
*
* @param string $number The number to convert, positive or zero, only digits.
*
* @return string
*/
private function toBinary(string $number) : string
{
@ -728,8 +642,6 @@ abstract class Calculator
* Returns the positive decimal representation of a binary number.
*
* @param string $bytes The bytes representing the number.
*
* @return string
*/
private function toDecimal(string $bytes) : string
{

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Brick\Math\Internal\Calculator;
use Brick\Math\Internal\Calculator;
use Override;
/**
* Calculator implementation built around the bcmath library.
@ -15,100 +16,58 @@ use Brick\Math\Internal\Calculator;
*/
class BcMathCalculator extends Calculator
{
/**
* {@inheritdoc}
*/
#[Override]
public function add(string $a, string $b) : string
{
return \bcadd($a, $b, 0);
}
/**
* {@inheritdoc}
*/
#[Override]
public function sub(string $a, string $b) : string
{
return \bcsub($a, $b, 0);
}
/**
* {@inheritdoc}
*/
#[Override]
public function mul(string $a, string $b) : string
{
return \bcmul($a, $b, 0);
}
/**
* {@inheritdoc}
*
* @psalm-suppress InvalidNullableReturnType
* @psalm-suppress NullableReturnStatement
*/
#[Override]
public function divQ(string $a, string $b) : string
{
return \bcdiv($a, $b, 0);
}
/**
* {@inheritdoc}
*
* @psalm-suppress InvalidNullableReturnType
* @psalm-suppress NullableReturnStatement
*/
#[Override]
public function divR(string $a, string $b) : string
{
if (version_compare(PHP_VERSION, '7.2') >= 0) {
return \bcmod($a, $b, 0);
}
return \bcmod($a, $b);
}
/**
* {@inheritdoc}
*/
#[Override]
public function divQR(string $a, string $b) : array
{
$q = \bcdiv($a, $b, 0);
if (version_compare(PHP_VERSION, '7.2') >= 0) {
$r = \bcmod($a, $b, 0);
} else {
$r = \bcmod($a, $b);
}
assert($q !== null);
assert($r !== null);
return [$q, $r];
}
/**
* {@inheritdoc}
*/
#[Override]
public function pow(string $a, int $e) : string
{
return \bcpow($a, (string) $e, 0);
}
/**
* {@inheritdoc}
*
* @psalm-suppress InvalidNullableReturnType
* @psalm-suppress NullableReturnStatement
*/
#[Override]
public function modPow(string $base, string $exp, string $mod) : string
{
return \bcpowmod($base, $exp, $mod, 0);
}
/**
* {@inheritDoc}
*
* @psalm-suppress NullableReturnStatement
* @psalm-suppress InvalidNullableReturnType
*/
#[Override]
public function sqrt(string $n) : string
{
return \bcsqrt($n, 0);

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Brick\Math\Internal\Calculator;
use Brick\Math\Internal\Calculator;
use Override;
/**
* Calculator implementation built around the GMP library.
@ -15,49 +16,37 @@ use Brick\Math\Internal\Calculator;
*/
class GmpCalculator extends Calculator
{
/**
* {@inheritdoc}
*/
#[Override]
public function add(string $a, string $b) : string
{
return \gmp_strval(\gmp_add($a, $b));
}
/**
* {@inheritdoc}
*/
#[Override]
public function sub(string $a, string $b) : string
{
return \gmp_strval(\gmp_sub($a, $b));
}
/**
* {@inheritdoc}
*/
#[Override]
public function mul(string $a, string $b) : string
{
return \gmp_strval(\gmp_mul($a, $b));
}
/**
* {@inheritdoc}
*/
#[Override]
public function divQ(string $a, string $b) : string
{
return \gmp_strval(\gmp_div_q($a, $b));
}
/**
* {@inheritdoc}
*/
#[Override]
public function divR(string $a, string $b) : string
{
return \gmp_strval(\gmp_div_r($a, $b));
}
/**
* {@inheritdoc}
*/
#[Override]
public function divQR(string $a, string $b) : array
{
[$q, $r] = \gmp_div_qr($a, $b);
@ -68,17 +57,13 @@ class GmpCalculator extends Calculator
];
}
/**
* {@inheritdoc}
*/
#[Override]
public function pow(string $a, int $e) : string
{
return \gmp_strval(\gmp_pow($a, $e));
}
/**
* {@inheritdoc}
*/
#[Override]
public function modInverse(string $x, string $m) : ?string
{
$result = \gmp_invert($x, $m);
@ -90,65 +75,49 @@ class GmpCalculator extends Calculator
return \gmp_strval($result);
}
/**
* {@inheritdoc}
*/
#[Override]
public function modPow(string $base, string $exp, string $mod) : string
{
return \gmp_strval(\gmp_powm($base, $exp, $mod));
}
/**
* {@inheritdoc}
*/
#[Override]
public function gcd(string $a, string $b) : string
{
return \gmp_strval(\gmp_gcd($a, $b));
}
/**
* {@inheritdoc}
*/
#[Override]
public function fromBase(string $number, int $base) : string
{
return \gmp_strval(\gmp_init($number, $base));
}
/**
* {@inheritdoc}
*/
#[Override]
public function toBase(string $number, int $base) : string
{
return \gmp_strval($number, $base);
}
/**
* {@inheritdoc}
*/
#[Override]
public function and(string $a, string $b) : string
{
return \gmp_strval(\gmp_and($a, $b));
}
/**
* {@inheritdoc}
*/
#[Override]
public function or(string $a, string $b) : string
{
return \gmp_strval(\gmp_or($a, $b));
}
/**
* {@inheritdoc}
*/
#[Override]
public function xor(string $a, string $b) : string
{
return \gmp_strval(\gmp_xor($a, $b));
}
/**
* {@inheritDoc}
*/
#[Override]
public function sqrt(string $n) : string
{
return \gmp_strval(\gmp_sqrt($n));

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Brick\Math\Internal\Calculator;
use Brick\Math\Internal\Calculator;
use Override;
/**
* Calculator implementation using only native PHP code.
@ -19,38 +20,25 @@ class NativeCalculator extends Calculator
* The max number of digits the platform can natively add, subtract, multiply or divide without overflow.
* For multiplication, this represents the max sum of the lengths of both operands.
*
* For addition, it is assumed that an extra digit can hold a carry (1) without overflowing.
* In addition, it is assumed that an extra digit can hold a carry (1) without overflowing.
* Example: 32-bit: max number 1,999,999,999 (9 digits + carry)
* 64-bit: max number 1,999,999,999,999,999,999 (18 digits + carry)
*
* @var int
*/
private $maxDigits;
private readonly int $maxDigits;
/**
* Class constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
switch (PHP_INT_SIZE) {
case 4:
$this->maxDigits = 9;
break;
case 8:
$this->maxDigits = 18;
break;
default:
throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.');
}
$this->maxDigits = match (PHP_INT_SIZE) {
4 => 9,
8 => 18,
default => throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.')
};
}
/**
* {@inheritdoc}
*/
#[Override]
public function add(string $a, string $b) : string
{
/**
@ -82,17 +70,13 @@ class NativeCalculator extends Calculator
return $result;
}
/**
* {@inheritdoc}
*/
#[Override]
public function sub(string $a, string $b) : string
{
return $this->add($a, $this->neg($b));
}
/**
* {@inheritdoc}
*/
#[Override]
public function mul(string $a, string $b) : string
{
/**
@ -136,25 +120,19 @@ class NativeCalculator extends Calculator
return $result;
}
/**
* {@inheritdoc}
*/
#[Override]
public function divQ(string $a, string $b) : string
{
return $this->divQR($a, $b)[0];
}
/**
* {@inheritdoc}
*/
#[Override]
public function divR(string $a, string $b): string
{
return $this->divQR($a, $b)[1];
}
/**
* {@inheritdoc}
*/
#[Override]
public function divQR(string $a, string $b) : array
{
if ($a === '0') {
@ -183,10 +161,8 @@ class NativeCalculator extends Calculator
if (is_int($nb)) {
// the only division that may overflow is PHP_INT_MIN / -1,
// which cannot happen here as we've already handled a divisor of -1 above.
$q = intdiv($na, $nb);
$r = $na % $nb;
$q = ($na - $r) / $nb;
assert(is_int($q));
return [
(string) $q,
@ -210,9 +186,7 @@ class NativeCalculator extends Calculator
return [$q, $r];
}
/**
* {@inheritdoc}
*/
#[Override]
public function pow(string $a, int $e) : string
{
if ($e === 0) {
@ -240,9 +214,8 @@ class NativeCalculator extends Calculator
/**
* Algorithm from: https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/
*
* {@inheritdoc}
*/
#[Override]
public function modPow(string $base, string $exp, string $mod) : string
{
// special case: the algorithm below fails with 0 power 0 mod 1 (returns 1 instead of 0)
@ -276,9 +249,8 @@ class NativeCalculator extends Calculator
/**
* Adapted from https://cp-algorithms.com/num_methods/roots_newton.html
*
* {@inheritDoc}
*/
#[Override]
public function sqrt(string $n) : string
{
if ($n === '0') {
@ -306,11 +278,6 @@ class NativeCalculator extends Calculator
/**
* Performs the addition of two non-signed large integers.
*
* @param string $a The first operand.
* @param string $b The second operand.
*
* @return string
*/
private function doAdd(string $a, string $b) : string
{
@ -363,11 +330,6 @@ class NativeCalculator extends Calculator
/**
* Performs the subtraction of two non-signed large integers.
*
* @param string $a The first operand.
* @param string $b The second operand.
*
* @return string
*/
private function doSub(string $a, string $b) : string
{
@ -445,11 +407,6 @@ class NativeCalculator extends Calculator
/**
* Performs the multiplication of two non-signed large integers.
*
* @param string $a The first operand.
* @param string $b The second operand.
*
* @return string
*/
private function doMul(string $a, string $b) : string
{
@ -522,9 +479,6 @@ class NativeCalculator extends Calculator
/**
* Performs the division of two non-signed large integers.
*
* @param string $a The first operand.
* @param string $b The second operand.
*
* @return string[] The quotient and remainder.
*/
private function doDiv(string $a, string $b) : array
@ -544,6 +498,22 @@ class NativeCalculator extends Calculator
$r = $a; // remainder
$z = $y; // focus length, always $y or $y+1
/** @psalm-var numeric-string $b */
$nb = $b * 1; // cast to number
// performance optimization in cases where the remainder will never cause int overflow
if (is_int(($nb - 1) * 10 + 9)) {
$r = (int) \substr($a, 0, $z - 1);
for ($i = $z - 1; $i < $x; $i++) {
$n = $r * 10 + (int) $a[$i];
/** @psalm-var int $nb */
$q .= \intdiv($n, $nb);
$r = $n % $nb;
}
return [\ltrim($q, '0') ?: '0', (string) $r];
}
for (;;) {
$focus = \substr($a, 0, $z);
@ -583,10 +553,7 @@ class NativeCalculator extends Calculator
/**
* Compares two non-signed large numbers.
*
* @param string $a The first operand.
* @param string $b The second operand.
*
* @return int [-1, 0, 1]
* @psalm-return -1|0|1
*/
private function doCmp(string $a, string $b) : int
{
@ -599,7 +566,7 @@ class NativeCalculator extends Calculator
return $cmp;
}
return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1]
return \strcmp($a, $b) <=> 0; // enforce -1|0|1
}
/**
@ -607,9 +574,6 @@ class NativeCalculator extends Calculator
*
* The numbers must only consist of digits, without leading minus sign.
*
* @param string $a The first operand.
* @param string $b The second operand.
*
* @return array{string, string, int}
*/
private function pad(string $a, string $b) : array

View file

@ -13,24 +13,15 @@ namespace Brick\Math;
* regardless the digits' contribution to the value of the number. In other words, considered
* as a numerical value, the discarded fraction could have an absolute value greater than one.
*/
final class RoundingMode
enum RoundingMode
{
/**
* Private constructor. This class is not instantiable.
*
* @codeCoverageIgnore
*/
private function __construct()
{
}
/**
* Asserts that the requested operation has an exact result, hence no rounding is necessary.
*
* If this rounding mode is specified on an operation that yields a result that
* cannot be represented at the requested scale, a RoundingNecessaryException is thrown.
*/
public const UNNECESSARY = 0;
case UNNECESSARY;
/**
* Rounds away from zero.
@ -38,7 +29,7 @@ final class RoundingMode
* Always increments the digit prior to a nonzero discarded fraction.
* Note that this rounding mode never decreases the magnitude of the calculated value.
*/
public const UP = 1;
case UP;
/**
* Rounds towards zero.
@ -46,7 +37,7 @@ final class RoundingMode
* Never increments the digit prior to a discarded fraction (i.e., truncates).
* Note that this rounding mode never increases the magnitude of the calculated value.
*/
public const DOWN = 2;
case DOWN;
/**
* Rounds towards positive infinity.
@ -54,7 +45,7 @@ final class RoundingMode
* If the result is positive, behaves as for UP; if negative, behaves as for DOWN.
* Note that this rounding mode never decreases the calculated value.
*/
public const CEILING = 3;
case CEILING;
/**
* Rounds towards negative infinity.
@ -62,7 +53,7 @@ final class RoundingMode
* If the result is positive, behave as for DOWN; if negative, behave as for UP.
* Note that this rounding mode never increases the calculated value.
*/
public const FLOOR = 4;
case FLOOR;
/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
@ -70,28 +61,28 @@ final class RoundingMode
* Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves as for DOWN.
* Note that this is the rounding mode commonly taught at school.
*/
public const HALF_UP = 5;
case HALF_UP;
/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
*
* Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN.
*/
public const HALF_DOWN = 6;
case HALF_DOWN;
/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity.
*
* If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN.
*/
public const HALF_CEILING = 7;
case HALF_CEILING;
/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity.
*
* If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP.
*/
public const HALF_FLOOR = 8;
case HALF_FLOOR;
/**
* Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor.
@ -103,5 +94,5 @@ final class RoundingMode
* cumulative error when applied repeatedly over a sequence of calculations.
* It is sometimes known as "Banker's rounding", and is chiefly used in the USA.
*/
public const HALF_EVEN = 9;
case HALF_EVEN;
}

View file

@ -6,7 +6,6 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));
return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'DateError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
'DateException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
@ -17,97 +16,7 @@ return array(
'DateMalformedStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
'DateObjectError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
'DateRangeError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'Override' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/Override.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'SQLite3Exception' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
'Safe\\DateTime' => $vendorDir . '/thecodingmachine/safe/lib/DateTime.php',
'Safe\\DateTimeImmutable' => $vendorDir . '/thecodingmachine/safe/lib/DateTimeImmutable.php',
'Safe\\Exceptions\\ApacheException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ApacheException.php',
'Safe\\Exceptions\\ApcException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/ApcException.php',
'Safe\\Exceptions\\ApcuException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ApcuException.php',
'Safe\\Exceptions\\ArrayException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ArrayException.php',
'Safe\\Exceptions\\Bzip2Exception' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/Bzip2Exception.php',
'Safe\\Exceptions\\CalendarException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/CalendarException.php',
'Safe\\Exceptions\\ClassobjException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ClassobjException.php',
'Safe\\Exceptions\\ComException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ComException.php',
'Safe\\Exceptions\\CubridException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/CubridException.php',
'Safe\\Exceptions\\CurlException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/CurlException.php',
'Safe\\Exceptions\\DatetimeException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/DatetimeException.php',
'Safe\\Exceptions\\DirException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/DirException.php',
'Safe\\Exceptions\\EioException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/EioException.php',
'Safe\\Exceptions\\ErrorfuncException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ErrorfuncException.php',
'Safe\\Exceptions\\ExecException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ExecException.php',
'Safe\\Exceptions\\FileinfoException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FileinfoException.php',
'Safe\\Exceptions\\FilesystemException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FilesystemException.php',
'Safe\\Exceptions\\FilterException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FilterException.php',
'Safe\\Exceptions\\FpmException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FpmException.php',
'Safe\\Exceptions\\FtpException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FtpException.php',
'Safe\\Exceptions\\FunchandException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/FunchandException.php',
'Safe\\Exceptions\\GettextException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/GettextException.php',
'Safe\\Exceptions\\GmpException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/GmpException.php',
'Safe\\Exceptions\\GnupgException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/GnupgException.php',
'Safe\\Exceptions\\HashException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/HashException.php',
'Safe\\Exceptions\\IbaseException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/IbaseException.php',
'Safe\\Exceptions\\IbmDb2Exception' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/IbmDb2Exception.php',
'Safe\\Exceptions\\IconvException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/IconvException.php',
'Safe\\Exceptions\\ImageException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ImageException.php',
'Safe\\Exceptions\\ImapException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ImapException.php',
'Safe\\Exceptions\\InfoException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/InfoException.php',
'Safe\\Exceptions\\InotifyException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/InotifyException.php',
'Safe\\Exceptions\\JsonException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/JsonException.php',
'Safe\\Exceptions\\LdapException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/LdapException.php',
'Safe\\Exceptions\\LibeventException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/LibeventException.php',
'Safe\\Exceptions\\LibxmlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/LibxmlException.php',
'Safe\\Exceptions\\LzfException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/LzfException.php',
'Safe\\Exceptions\\MailparseException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MailparseException.php',
'Safe\\Exceptions\\MbstringException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MbstringException.php',
'Safe\\Exceptions\\MiscException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MiscException.php',
'Safe\\Exceptions\\MssqlException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/MssqlException.php',
'Safe\\Exceptions\\MysqlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MysqlException.php',
'Safe\\Exceptions\\MysqliException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/MysqliException.php',
'Safe\\Exceptions\\NetworkException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/NetworkException.php',
'Safe\\Exceptions\\Oci8Exception' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/Oci8Exception.php',
'Safe\\Exceptions\\OpcacheException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/OpcacheException.php',
'Safe\\Exceptions\\OpensslException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/OpensslException.php',
'Safe\\Exceptions\\OutcontrolException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/OutcontrolException.php',
'Safe\\Exceptions\\PasswordException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/PasswordException.php',
'Safe\\Exceptions\\PcntlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PcntlException.php',
'Safe\\Exceptions\\PcreException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/PcreException.php',
'Safe\\Exceptions\\PgsqlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PgsqlException.php',
'Safe\\Exceptions\\PosixException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PosixException.php',
'Safe\\Exceptions\\PsException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PsException.php',
'Safe\\Exceptions\\PspellException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PspellException.php',
'Safe\\Exceptions\\ReadlineException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ReadlineException.php',
'Safe\\Exceptions\\RpminfoException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/RpminfoException.php',
'Safe\\Exceptions\\RrdException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/RrdException.php',
'Safe\\Exceptions\\SafeExceptionInterface' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php',
'Safe\\Exceptions\\SemException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SemException.php',
'Safe\\Exceptions\\SessionException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SessionException.php',
'Safe\\Exceptions\\ShmopException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ShmopException.php',
'Safe\\Exceptions\\SimplexmlException' => $vendorDir . '/thecodingmachine/safe/lib/Exceptions/SimplexmlException.php',
'Safe\\Exceptions\\SocketsException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SocketsException.php',
'Safe\\Exceptions\\SodiumException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SodiumException.php',
'Safe\\Exceptions\\SolrException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SolrException.php',
'Safe\\Exceptions\\SplException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SplException.php',
'Safe\\Exceptions\\SqlsrvException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SqlsrvException.php',
'Safe\\Exceptions\\SsdeepException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SsdeepException.php',
'Safe\\Exceptions\\Ssh2Exception' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/Ssh2Exception.php',
'Safe\\Exceptions\\StatsException' => $vendorDir . '/thecodingmachine/safe/deprecated/Exceptions/StatsException.php',
'Safe\\Exceptions\\StreamException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/StreamException.php',
'Safe\\Exceptions\\StringsException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/StringsException.php',
'Safe\\Exceptions\\SwooleException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/SwooleException.php',
'Safe\\Exceptions\\UodbcException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/UodbcException.php',
'Safe\\Exceptions\\UopzException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/UopzException.php',
'Safe\\Exceptions\\UrlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/UrlException.php',
'Safe\\Exceptions\\VarException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/VarException.php',
'Safe\\Exceptions\\XdiffException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/XdiffException.php',
'Safe\\Exceptions\\XmlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/XmlException.php',
'Safe\\Exceptions\\XmlrpcException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/XmlrpcException.php',
'Safe\\Exceptions\\YamlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/YamlException.php',
'Safe\\Exceptions\\YazException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/YazException.php',
'Safe\\Exceptions\\ZipException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ZipException.php',
'Safe\\Exceptions\\ZlibException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/ZlibException.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);

View file

@ -6,107 +6,22 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));
return array(
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
'a4ecaeafb8cfb009ad0e052c90355e98' => $vendorDir . '/beberlei/assert/lib/Assert/functions.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
'3109cb1a231dcd04bee1f9f620d46975' => $vendorDir . '/paragonie/sodium_compat/autoload.php',
'662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',
'5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
'72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'2203a247e6fda86070a5e4e07aed533a' => $vendorDir . '/symfony/clock/Resources/now.php',
'09f6b20656683369174dd6fa83b7e5fb' => $vendorDir . '/symfony/polyfill-uuid/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
'c2b3214084883d700175de676a4fc127' => $vendorDir . '/facile-it/php-jose-verifier/src/functions/derived_key.php',
'16040cf78e404de30085045d3863ed51' => $vendorDir . '/facile-it/php-jose-verifier/src/functions/jose_secret_key.php',
'5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
'51fcf4e06c07cc00c920b44bcd900e7a' => $vendorDir . '/thecodingmachine/safe/deprecated/apc.php',
'288267919fedd3829a7732b5fb202197' => $vendorDir . '/thecodingmachine/safe/deprecated/array.php',
'a88cd08cfbf1600f7d5de6e587eee1fa' => $vendorDir . '/thecodingmachine/safe/deprecated/datetime.php',
'47f619d9197b36cf5ab70738d7743fe2' => $vendorDir . '/thecodingmachine/safe/deprecated/libevent.php',
'f1f7d69cca064c8f779d4a4cba463e11' => $vendorDir . '/thecodingmachine/safe/deprecated/misc.php',
'213c1c2258e2e5aa409a0af3e993b3a9' => $vendorDir . '/thecodingmachine/safe/deprecated/password.php',
'ea6bb8a12ef9b68f6ada99058e530760' => $vendorDir . '/thecodingmachine/safe/deprecated/mssql.php',
'9a29089eb3ce41a446744c68a00f118c' => $vendorDir . '/thecodingmachine/safe/deprecated/stats.php',
'd5947c9df62650029c674c79176af68d' => $vendorDir . '/thecodingmachine/safe/deprecated/strings.php',
'72243e5536b63e298acb6476f01f1aff' => $vendorDir . '/thecodingmachine/safe/lib/special_cases.php',
'09f92ed6301edc510574c196c2b7d1af' => $vendorDir . '/thecodingmachine/safe/deprecated/mysqli.php',
'3f648889e687f31c52f949ba8a9d0873' => $vendorDir . '/thecodingmachine/safe/generated/apache.php',
'eeb4581d958421a4244aaa4167c6a575' => $vendorDir . '/thecodingmachine/safe/generated/apcu.php',
'04cb0b3c1dac5b5ddb23c14e3d66dbe9' => $vendorDir . '/thecodingmachine/safe/generated/array.php',
'450b332a74a9a21e043c5e953485a791' => $vendorDir . '/thecodingmachine/safe/generated/bzip2.php',
'6e9b7954ecfd7cbb9ca239319d1acdb6' => $vendorDir . '/thecodingmachine/safe/generated/calendar.php',
'2c6d7e8bd2de9a272a9d4d43b0a4304a' => $vendorDir . '/thecodingmachine/safe/generated/classobj.php',
'0b8231c1ad0865447c988a4c16b4001f' => $vendorDir . '/thecodingmachine/safe/generated/com.php',
'7643a71fe1c3256058c8fee234cb86e5' => $vendorDir . '/thecodingmachine/safe/generated/cubrid.php',
'68e1365710575942efc1d55000032cee' => $vendorDir . '/thecodingmachine/safe/generated/curl.php',
'02fd26bca803106c5b942a7197c3ad8b' => $vendorDir . '/thecodingmachine/safe/generated/datetime.php',
'f4817dcbd956cd221b1c31f6fbd5749c' => $vendorDir . '/thecodingmachine/safe/generated/dir.php',
'51c3f2d10ca61a70dbcea0e38d8e902d' => $vendorDir . '/thecodingmachine/safe/generated/eio.php',
'1d34f34327ca3e81535963016e3be2c3' => $vendorDir . '/thecodingmachine/safe/generated/errorfunc.php',
'4fd0ba2d3717b0424d474bebfdafa2b4' => $vendorDir . '/thecodingmachine/safe/generated/exec.php',
'98f4dae054bc7fb19c13be14935cbdd3' => $vendorDir . '/thecodingmachine/safe/generated/fileinfo.php',
'5530ae063ba88323eaf0a07904efdf85' => $vendorDir . '/thecodingmachine/safe/generated/filesystem.php',
'633f4f134975d70e97bddad83348e91a' => $vendorDir . '/thecodingmachine/safe/generated/filter.php',
'fbd163fc68c5faf73d5ed4002ffd836d' => $vendorDir . '/thecodingmachine/safe/generated/fpm.php',
'21b511999d61411fab0692ff8795bbed' => $vendorDir . '/thecodingmachine/safe/generated/ftp.php',
'85fbd73fc92365cd90526b0ea03cae3a' => $vendorDir . '/thecodingmachine/safe/generated/funchand.php',
'a2e4c6dfdbf36f56f1945ddcbd54e289' => $vendorDir . '/thecodingmachine/safe/generated/gettext.php',
'51df9c146e0b7dcbdf358d8abd24dbdc' => $vendorDir . '/thecodingmachine/safe/generated/gmp.php',
'93bb7fe678d7dcfb1322f8e3475a48b0' => $vendorDir . '/thecodingmachine/safe/generated/gnupg.php',
'c171ba99cf316379ff66468392bf4950' => $vendorDir . '/thecodingmachine/safe/generated/hash.php',
'5ab4aad4c28e468209fbfcceb2e5e6a5' => $vendorDir . '/thecodingmachine/safe/generated/ibase.php',
'4d57409c5e8e576b0c64c08d9d731cfb' => $vendorDir . '/thecodingmachine/safe/generated/ibmDb2.php',
'eeb246d5403972a9d62106e4a4883496' => $vendorDir . '/thecodingmachine/safe/generated/iconv.php',
'c28a05f498c01b810a714f7214b7a8da' => $vendorDir . '/thecodingmachine/safe/generated/image.php',
'8063cd92acdf00fd978b5599eb7cc142' => $vendorDir . '/thecodingmachine/safe/generated/imap.php',
'8bd26dbe768e9c9599edad7b198e5446' => $vendorDir . '/thecodingmachine/safe/generated/info.php',
'd4362910bde43c0f956b52527effd7d4' => $vendorDir . '/thecodingmachine/safe/generated/inotify.php',
'696ba49197d9b55f0428a12bb5a818e1' => $vendorDir . '/thecodingmachine/safe/generated/json.php',
'9818aaa99c8647c63f8ef62b7a368160' => $vendorDir . '/thecodingmachine/safe/generated/ldap.php',
'bcf523ff2a195eb08e0fbb668ed784d0' => $vendorDir . '/thecodingmachine/safe/generated/libxml.php',
'68be68a9a8b95bb56cab6109ff03bc88' => $vendorDir . '/thecodingmachine/safe/generated/lzf.php',
'bdca804bb0904ea9f53f328dfc0bb8a5' => $vendorDir . '/thecodingmachine/safe/generated/mailparse.php',
'b0a3fcac3eaf55445796d6af26b89366' => $vendorDir . '/thecodingmachine/safe/generated/mbstring.php',
'98de16b8db03eb0cb4d318b4402215a6' => $vendorDir . '/thecodingmachine/safe/generated/misc.php',
'7cefd81607cd21b8b3a15656eb6465f5' => $vendorDir . '/thecodingmachine/safe/generated/mysql.php',
'cbac956836b72483dcff1ac39d5c0a0f' => $vendorDir . '/thecodingmachine/safe/generated/network.php',
'6c8f89dfbdc117d7871f572269363f25' => $vendorDir . '/thecodingmachine/safe/generated/oci8.php',
'169a669966a45c06bf55ed029122729b' => $vendorDir . '/thecodingmachine/safe/generated/opcache.php',
'def61bf4fecd4d4bca7354919cd69302' => $vendorDir . '/thecodingmachine/safe/generated/openssl.php',
'26bb010649a6d32d4120181458aa6ef2' => $vendorDir . '/thecodingmachine/safe/generated/outcontrol.php',
'002ebcb842e2c0d5b7f67fe64cc93158' => $vendorDir . '/thecodingmachine/safe/generated/pcntl.php',
'86df38612982dade72c7085ce7eca81f' => $vendorDir . '/thecodingmachine/safe/generated/pcre.php',
'1fc22f445c69ea8706e82fce301c0831' => $vendorDir . '/thecodingmachine/safe/generated/pgsql.php',
'c70b42561584f7144bff38cd63c4eef3' => $vendorDir . '/thecodingmachine/safe/generated/posix.php',
'9923214639c32ca5173db03a177d3b63' => $vendorDir . '/thecodingmachine/safe/generated/ps.php',
'7e9c3f8eae2b5bf42205c4f1295cb7a7' => $vendorDir . '/thecodingmachine/safe/generated/pspell.php',
'91aa91f6245c349c2e2e88bd0025f199' => $vendorDir . '/thecodingmachine/safe/generated/readline.php',
'd43773cacb9e5e8e897aa255e32007d1' => $vendorDir . '/thecodingmachine/safe/generated/rpminfo.php',
'f053a3849e9e8383762b34b91db0320b' => $vendorDir . '/thecodingmachine/safe/generated/rrd.php',
'775b964f72f827a1bf87c65ab5b10800' => $vendorDir . '/thecodingmachine/safe/generated/sem.php',
'816428bd69c29ab5e1ed622af5dca0cd' => $vendorDir . '/thecodingmachine/safe/generated/session.php',
'5093e233bedbefaef0df262bfbab0a5c' => $vendorDir . '/thecodingmachine/safe/generated/shmop.php',
'b080617b1d949683c2e37f8f01dc0e15' => $vendorDir . '/thecodingmachine/safe/generated/sockets.php',
'2708aa182ddcfe6ce27c96acaaa40f69' => $vendorDir . '/thecodingmachine/safe/generated/sodium.php',
'f1b96cb260a5baeea9a7285cda82a1ec' => $vendorDir . '/thecodingmachine/safe/generated/solr.php',
'3fd8853757d0fe3557c179efb807afeb' => $vendorDir . '/thecodingmachine/safe/generated/spl.php',
'9312ce96a51c846913fcda5f186d58dd' => $vendorDir . '/thecodingmachine/safe/generated/sqlsrv.php',
'd3eb383ad0b8b962b29dc4afd29d6715' => $vendorDir . '/thecodingmachine/safe/generated/ssdeep.php',
'42a09bc448f441a0b9f9367ea975c0bf' => $vendorDir . '/thecodingmachine/safe/generated/ssh2.php',
'ef711077d356d1b33ca0b10b67b0be8f' => $vendorDir . '/thecodingmachine/safe/generated/stream.php',
'764b09f6df081cbb2807b97c6ace3866' => $vendorDir . '/thecodingmachine/safe/generated/strings.php',
'ef241678769fee4a44aaa288f3b78aa1' => $vendorDir . '/thecodingmachine/safe/generated/swoole.php',
'0efc8f6778cba932b9e2a89e28de2452' => $vendorDir . '/thecodingmachine/safe/generated/uodbc.php',
'd383d32907b98af53ee9208c62204fd0' => $vendorDir . '/thecodingmachine/safe/generated/uopz.php',
'2fd2e4060f7fe772660f002ce38f0b71' => $vendorDir . '/thecodingmachine/safe/generated/url.php',
'782249e03deebeaf57b9991ff5493aa0' => $vendorDir . '/thecodingmachine/safe/generated/var.php',
'344440cd1cd7200fdb4f12af0d3c587f' => $vendorDir . '/thecodingmachine/safe/generated/xdiff.php',
'3599f369219c658a5fb6c4fe66832f62' => $vendorDir . '/thecodingmachine/safe/generated/xml.php',
'7fcd313da9fae337051b091b3492c21b' => $vendorDir . '/thecodingmachine/safe/generated/xmlrpc.php',
'd668c74cfa92d893b582356733d9a80e' => $vendorDir . '/thecodingmachine/safe/generated/yaml.php',
'4af1dca6db8c527c6eed27bff85ff0e5' => $vendorDir . '/thecodingmachine/safe/generated/yaz.php',
'fe43ca06499ac37bc2dedd823af71eb5' => $vendorDir . '/thecodingmachine/safe/generated/zip.php',
'356736db98a6834f0a886b8d509b0ecd' => $vendorDir . '/thecodingmachine/safe/generated/zlib.php',
'ba61337b858c088ff9f16a5fc3badbeb' => $vendorDir . '/facile-it/php-openid-client/src/functions/base64url_decode.php',
'd4a8a901fd39fc07eb96403508f8f03f' => $vendorDir . '/facile-it/php-openid-client/src/functions/base64url_encode.php',
'c81c91c32460d498a356b65d5a21fc4c' => $vendorDir . '/facile-it/php-openid-client/src/functions/check_server_response.php',

View file

@ -6,41 +6,42 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));
return array(
'voku\\' => array($vendorDir . '/voku/portable-ascii/src/voku'),
'phpseclib3\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
'Webklex\\PHPIMAP\\' => array($vendorDir . '/webklex/php-imap/src'),
'Webauthn\\MetadataService\\' => array($vendorDir . '/web-auth/metadata-service/src'),
'Webauthn\\' => array($vendorDir . '/web-auth/webauthn-lib/src'),
'Symfony\\Polyfill\\Uuid\\' => array($vendorDir . '/symfony/polyfill-uuid'),
'Symfony\\Polyfill\\Php83\\' => array($vendorDir . '/symfony/polyfill-php83'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
'Symfony\\Polyfill\\Intl\\Grapheme\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'),
'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
'Symfony\\Contracts\\HttpClient\\' => array($vendorDir . '/symfony/http-client-contracts'),
'Symfony\\Component\\Uid\\' => array($vendorDir . '/symfony/uid'),
'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'),
'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
'Symfony\\Component\\HttpClient\\' => array($vendorDir . '/symfony/http-client'),
'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
'Symfony\\Component\\Clock\\' => array($vendorDir . '/symfony/clock'),
'Symfony\\Bridge\\PsrHttpMessage\\' => array($vendorDir . '/symfony/psr-http-message-bridge'),
'SpomkyLabs\\Pki\\' => array($vendorDir . '/spomky-labs/pki-framework/src'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/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'),
'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'),
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'Jose\\Easy\\' => array($vendorDir . '/web-token/jwt-easy'),
'Jose\\Component\\Signature\\Algorithm\\' => array($vendorDir . '/web-token/jwt-signature-algorithm-rsa'),
'Jose\\Component\\Signature\\' => array($vendorDir . '/web-token/jwt-signature'),
'Jose\\Component\\KeyManagement\\' => array($vendorDir . '/web-token/jwt-key-mgmt'),
'Jose\\Component\\Encryption\\' => array($vendorDir . '/web-token/jwt-encryption'),
'Jose\\Component\\Core\\' => array($vendorDir . '/web-token/jwt-core'),
'Jose\\Component\\Checker\\' => array($vendorDir . '/web-token/jwt-checker'),
'Illuminate\\Support\\' => array($vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/conditionable', $vendorDir . '/illuminate/macroable', $vendorDir . '/illuminate/support'),
'Lcobucci\\Clock\\' => array($vendorDir . '/lcobucci/clock/src'),
'Jose\\Component\\' => array($vendorDir . '/web-token/jwt-library'),
'Illuminate\\Support\\' => array($vendorDir . '/illuminate/support'),
'Illuminate\\Pagination\\' => array($vendorDir . '/illuminate/pagination'),
'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'),
'Http\\Factory\\Guzzle\\' => array($vendorDir . '/http-interop/http-factory-guzzle/src'),
@ -49,9 +50,9 @@ return array(
'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
'Facile\\OpenIDClient\\' => array($vendorDir . '/facile-it/php-openid-client/src'),
'Facile\\JoseVerifier\\' => array($vendorDir . '/facile-it/php-jose-verifier/src'),
'FG\\' => array($vendorDir . '/fgrosse/phpasn1/lib'),
'Duo\\DuoUniversal\\' => array($vendorDir . '/duosecurity/duo_universal_php/src'),
'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'),
'Doctrine\\Common\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Common/Inflector'),
'Cose\\' => array($vendorDir . '/web-auth/cose-lib/src'),
'Carbon\\Doctrine\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'),
'Carbon\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'),
@ -59,5 +60,4 @@ return array(
'Brick\\Math\\' => array($vendorDir . '/brick/math/src'),
'Base64Url\\' => array($vendorDir . '/spomky-labs/base64url/src'),
'Base32\\' => array($vendorDir . '/christian-riesen/base32/src'),
'Assert\\' => array($vendorDir . '/beberlei/assert/lib/Assert'),
);

View file

@ -7,107 +7,22 @@ namespace Composer\Autoload;
class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
{
public static $files = array (
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
'a4ecaeafb8cfb009ad0e052c90355e98' => __DIR__ . '/..' . '/beberlei/assert/lib/Assert/functions.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
'3109cb1a231dcd04bee1f9f620d46975' => __DIR__ . '/..' . '/paragonie/sodium_compat/autoload.php',
'662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php',
'5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
'72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'2203a247e6fda86070a5e4e07aed533a' => __DIR__ . '/..' . '/symfony/clock/Resources/now.php',
'09f6b20656683369174dd6fa83b7e5fb' => __DIR__ . '/..' . '/symfony/polyfill-uuid/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
'c2b3214084883d700175de676a4fc127' => __DIR__ . '/..' . '/facile-it/php-jose-verifier/src/functions/derived_key.php',
'16040cf78e404de30085045d3863ed51' => __DIR__ . '/..' . '/facile-it/php-jose-verifier/src/functions/jose_secret_key.php',
'5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
'51fcf4e06c07cc00c920b44bcd900e7a' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/apc.php',
'288267919fedd3829a7732b5fb202197' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/array.php',
'a88cd08cfbf1600f7d5de6e587eee1fa' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/datetime.php',
'47f619d9197b36cf5ab70738d7743fe2' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/libevent.php',
'f1f7d69cca064c8f779d4a4cba463e11' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/misc.php',
'213c1c2258e2e5aa409a0af3e993b3a9' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/password.php',
'ea6bb8a12ef9b68f6ada99058e530760' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/mssql.php',
'9a29089eb3ce41a446744c68a00f118c' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/stats.php',
'd5947c9df62650029c674c79176af68d' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/strings.php',
'72243e5536b63e298acb6476f01f1aff' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/special_cases.php',
'09f92ed6301edc510574c196c2b7d1af' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/mysqli.php',
'3f648889e687f31c52f949ba8a9d0873' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/apache.php',
'eeb4581d958421a4244aaa4167c6a575' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/apcu.php',
'04cb0b3c1dac5b5ddb23c14e3d66dbe9' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/array.php',
'450b332a74a9a21e043c5e953485a791' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/bzip2.php',
'6e9b7954ecfd7cbb9ca239319d1acdb6' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/calendar.php',
'2c6d7e8bd2de9a272a9d4d43b0a4304a' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/classobj.php',
'0b8231c1ad0865447c988a4c16b4001f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/com.php',
'7643a71fe1c3256058c8fee234cb86e5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/cubrid.php',
'68e1365710575942efc1d55000032cee' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/curl.php',
'02fd26bca803106c5b942a7197c3ad8b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/datetime.php',
'f4817dcbd956cd221b1c31f6fbd5749c' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/dir.php',
'51c3f2d10ca61a70dbcea0e38d8e902d' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/eio.php',
'1d34f34327ca3e81535963016e3be2c3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/errorfunc.php',
'4fd0ba2d3717b0424d474bebfdafa2b4' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/exec.php',
'98f4dae054bc7fb19c13be14935cbdd3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/fileinfo.php',
'5530ae063ba88323eaf0a07904efdf85' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/filesystem.php',
'633f4f134975d70e97bddad83348e91a' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/filter.php',
'fbd163fc68c5faf73d5ed4002ffd836d' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/fpm.php',
'21b511999d61411fab0692ff8795bbed' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ftp.php',
'85fbd73fc92365cd90526b0ea03cae3a' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/funchand.php',
'a2e4c6dfdbf36f56f1945ddcbd54e289' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/gettext.php',
'51df9c146e0b7dcbdf358d8abd24dbdc' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/gmp.php',
'93bb7fe678d7dcfb1322f8e3475a48b0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/gnupg.php',
'c171ba99cf316379ff66468392bf4950' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/hash.php',
'5ab4aad4c28e468209fbfcceb2e5e6a5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ibase.php',
'4d57409c5e8e576b0c64c08d9d731cfb' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ibmDb2.php',
'eeb246d5403972a9d62106e4a4883496' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/iconv.php',
'c28a05f498c01b810a714f7214b7a8da' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/image.php',
'8063cd92acdf00fd978b5599eb7cc142' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/imap.php',
'8bd26dbe768e9c9599edad7b198e5446' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/info.php',
'd4362910bde43c0f956b52527effd7d4' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/inotify.php',
'696ba49197d9b55f0428a12bb5a818e1' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/json.php',
'9818aaa99c8647c63f8ef62b7a368160' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ldap.php',
'bcf523ff2a195eb08e0fbb668ed784d0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/libxml.php',
'68be68a9a8b95bb56cab6109ff03bc88' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/lzf.php',
'bdca804bb0904ea9f53f328dfc0bb8a5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mailparse.php',
'b0a3fcac3eaf55445796d6af26b89366' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mbstring.php',
'98de16b8db03eb0cb4d318b4402215a6' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/misc.php',
'7cefd81607cd21b8b3a15656eb6465f5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysql.php',
'cbac956836b72483dcff1ac39d5c0a0f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/network.php',
'6c8f89dfbdc117d7871f572269363f25' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/oci8.php',
'169a669966a45c06bf55ed029122729b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/opcache.php',
'def61bf4fecd4d4bca7354919cd69302' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/openssl.php',
'26bb010649a6d32d4120181458aa6ef2' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/outcontrol.php',
'002ebcb842e2c0d5b7f67fe64cc93158' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pcntl.php',
'86df38612982dade72c7085ce7eca81f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pcre.php',
'1fc22f445c69ea8706e82fce301c0831' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pgsql.php',
'c70b42561584f7144bff38cd63c4eef3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/posix.php',
'9923214639c32ca5173db03a177d3b63' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ps.php',
'7e9c3f8eae2b5bf42205c4f1295cb7a7' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pspell.php',
'91aa91f6245c349c2e2e88bd0025f199' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/readline.php',
'd43773cacb9e5e8e897aa255e32007d1' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/rpminfo.php',
'f053a3849e9e8383762b34b91db0320b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/rrd.php',
'775b964f72f827a1bf87c65ab5b10800' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sem.php',
'816428bd69c29ab5e1ed622af5dca0cd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/session.php',
'5093e233bedbefaef0df262bfbab0a5c' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/shmop.php',
'b080617b1d949683c2e37f8f01dc0e15' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sockets.php',
'2708aa182ddcfe6ce27c96acaaa40f69' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sodium.php',
'f1b96cb260a5baeea9a7285cda82a1ec' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/solr.php',
'3fd8853757d0fe3557c179efb807afeb' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/spl.php',
'9312ce96a51c846913fcda5f186d58dd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sqlsrv.php',
'd3eb383ad0b8b962b29dc4afd29d6715' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ssdeep.php',
'42a09bc448f441a0b9f9367ea975c0bf' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ssh2.php',
'ef711077d356d1b33ca0b10b67b0be8f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/stream.php',
'764b09f6df081cbb2807b97c6ace3866' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/strings.php',
'ef241678769fee4a44aaa288f3b78aa1' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/swoole.php',
'0efc8f6778cba932b9e2a89e28de2452' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/uodbc.php',
'd383d32907b98af53ee9208c62204fd0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/uopz.php',
'2fd2e4060f7fe772660f002ce38f0b71' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/url.php',
'782249e03deebeaf57b9991ff5493aa0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/var.php',
'344440cd1cd7200fdb4f12af0d3c587f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/xdiff.php',
'3599f369219c658a5fb6c4fe66832f62' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/xml.php',
'7fcd313da9fae337051b091b3492c21b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/xmlrpc.php',
'd668c74cfa92d893b582356733d9a80e' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/yaml.php',
'4af1dca6db8c527c6eed27bff85ff0e5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/yaz.php',
'fe43ca06499ac37bc2dedd823af71eb5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/zip.php',
'356736db98a6834f0a886b8d509b0ecd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/zlib.php',
'ba61337b858c088ff9f16a5fc3badbeb' => __DIR__ . '/..' . '/facile-it/php-openid-client/src/functions/base64url_decode.php',
'd4a8a901fd39fc07eb96403508f8f03f' => __DIR__ . '/..' . '/facile-it/php-openid-client/src/functions/base64url_encode.php',
'c81c91c32460d498a356b65d5a21fc4c' => __DIR__ . '/..' . '/facile-it/php-openid-client/src/functions/check_server_response.php',
@ -120,10 +35,6 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
);
public static $prefixLengthsPsr4 = array (
'v' =>
array (
'voku\\' => 5,
),
'p' =>
array (
'phpseclib3\\' => 11,
@ -131,23 +42,28 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
'W' =>
array (
'Webklex\\PHPIMAP\\' => 16,
'Webauthn\\MetadataService\\' => 25,
'Webauthn\\' => 9,
),
'S' =>
array (
'Symfony\\Polyfill\\Uuid\\' => 22,
'Symfony\\Polyfill\\Php83\\' => 23,
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
'Symfony\\Polyfill\\Intl\\Grapheme\\' => 31,
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Contracts\\Translation\\' => 30,
'Symfony\\Contracts\\Service\\' => 26,
'Symfony\\Contracts\\HttpClient\\' => 29,
'Symfony\\Component\\Uid\\' => 22,
'Symfony\\Component\\Translation\\' => 30,
'Symfony\\Component\\String\\' => 25,
'Symfony\\Component\\HttpFoundation\\' => 33,
'Symfony\\Component\\HttpClient\\' => 29,
'Symfony\\Component\\Console\\' => 26,
'Symfony\\Component\\Clock\\' => 24,
'Symfony\\Bridge\\PsrHttpMessage\\' => 30,
'SpomkyLabs\\Pki\\' => 15,
),
'P' =>
array (
@ -156,8 +72,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
'Psr\\Http\\Server\\' => 16,
'Psr\\Http\\Message\\' => 17,
'Psr\\Http\\Client\\' => 16,
'Psr\\EventDispatcher\\' => 20,
'Psr\\Container\\' => 14,
'Psr\\Clock\\' => 10,
'Psr\\Cache\\' => 10,
'ParagonIE\\ConstantTime\\' => 23,
'PHPMailer\\PHPMailer\\' => 20,
),
@ -165,15 +83,13 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
'Monolog\\' => 8,
),
'L' =>
array (
'Lcobucci\\Clock\\' => 15,
),
'J' =>
array (
'Jose\\Easy\\' => 10,
'Jose\\Component\\Signature\\Algorithm\\' => 35,
'Jose\\Component\\Signature\\' => 25,
'Jose\\Component\\KeyManagement\\' => 29,
'Jose\\Component\\Encryption\\' => 26,
'Jose\\Component\\Core\\' => 20,
'Jose\\Component\\Checker\\' => 23,
'Jose\\Component\\' => 15,
),
'I' =>
array (
@ -195,12 +111,12 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
'Firebase\\JWT\\' => 13,
'Facile\\OpenIDClient\\' => 20,
'Facile\\JoseVerifier\\' => 20,
'FG\\' => 3,
),
'D' =>
array (
'Duo\\DuoUniversal\\' => 17,
'Doctrine\\Inflector\\' => 19,
'Doctrine\\Common\\Inflector\\' => 26,
),
'C' =>
array (
@ -215,17 +131,9 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
'Base64Url\\' => 10,
'Base32\\' => 7,
),
'A' =>
array (
'Assert\\' => 7,
),
);
public static $prefixDirsPsr4 = array (
'voku\\' =>
array (
0 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku',
),
'phpseclib3\\' =>
array (
0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
@ -234,10 +142,6 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/webklex/php-imap/src',
),
'Webauthn\\MetadataService\\' =>
array (
0 => __DIR__ . '/..' . '/web-auth/metadata-service/src',
),
'Webauthn\\' =>
array (
0 => __DIR__ . '/..' . '/web-auth/webauthn-lib/src',
@ -250,14 +154,22 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php83',
),
'Symfony\\Polyfill\\Php80\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Intl\\Normalizer\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',
),
'Symfony\\Polyfill\\Intl\\Grapheme\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme',
),
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'Symfony\\Contracts\\Translation\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/translation-contracts',
@ -278,6 +190,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/symfony/translation',
),
'Symfony\\Component\\String\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/string',
),
'Symfony\\Component\\HttpFoundation\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/http-foundation',
@ -286,10 +202,22 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/symfony/http-client',
),
'Symfony\\Component\\Console\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/console',
),
'Symfony\\Component\\Clock\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/clock',
),
'Symfony\\Bridge\\PsrHttpMessage\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/psr-http-message-bridge',
),
'SpomkyLabs\\Pki\\' =>
array (
0 => __DIR__ . '/..' . '/spomky-labs/pki-framework/src',
),
'Psr\\SimpleCache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/simple-cache/src',
@ -312,6 +240,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/psr/http-client/src',
),
'Psr\\EventDispatcher\\' =>
array (
0 => __DIR__ . '/..' . '/psr/event-dispatcher/src',
),
'Psr\\Container\\' =>
array (
0 => __DIR__ . '/..' . '/psr/container/src',
@ -320,6 +252,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/psr/clock/src',
),
'Psr\\Cache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/cache/src',
),
'ParagonIE\\ConstantTime\\' =>
array (
0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src',
@ -332,40 +268,17 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog',
),
'Jose\\Easy\\' =>
'Lcobucci\\Clock\\' =>
array (
0 => __DIR__ . '/..' . '/web-token/jwt-easy',
0 => __DIR__ . '/..' . '/lcobucci/clock/src',
),
'Jose\\Component\\Signature\\Algorithm\\' =>
'Jose\\Component\\' =>
array (
0 => __DIR__ . '/..' . '/web-token/jwt-signature-algorithm-rsa',
),
'Jose\\Component\\Signature\\' =>
array (
0 => __DIR__ . '/..' . '/web-token/jwt-signature',
),
'Jose\\Component\\KeyManagement\\' =>
array (
0 => __DIR__ . '/..' . '/web-token/jwt-key-mgmt',
),
'Jose\\Component\\Encryption\\' =>
array (
0 => __DIR__ . '/..' . '/web-token/jwt-encryption',
),
'Jose\\Component\\Core\\' =>
array (
0 => __DIR__ . '/..' . '/web-token/jwt-core',
),
'Jose\\Component\\Checker\\' =>
array (
0 => __DIR__ . '/..' . '/web-token/jwt-checker',
0 => __DIR__ . '/..' . '/web-token/jwt-library',
),
'Illuminate\\Support\\' =>
array (
0 => __DIR__ . '/..' . '/illuminate/collections',
1 => __DIR__ . '/..' . '/illuminate/conditionable',
2 => __DIR__ . '/..' . '/illuminate/macroable',
3 => __DIR__ . '/..' . '/illuminate/support',
0 => __DIR__ . '/..' . '/illuminate/support',
),
'Illuminate\\Pagination\\' =>
array (
@ -399,10 +312,6 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/facile-it/php-jose-verifier/src',
),
'FG\\' =>
array (
0 => __DIR__ . '/..' . '/fgrosse/phpasn1/lib',
),
'Duo\\DuoUniversal\\' =>
array (
0 => __DIR__ . '/..' . '/duosecurity/duo_universal_php/src',
@ -411,6 +320,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector',
),
'Doctrine\\Common\\Inflector\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Common/Inflector',
),
'Cose\\' =>
array (
0 => __DIR__ . '/..' . '/web-auth/cose-lib/src',
@ -439,14 +352,9 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
array (
0 => __DIR__ . '/..' . '/christian-riesen/base32/src',
),
'Assert\\' =>
array (
0 => __DIR__ . '/..' . '/beberlei/assert/lib/Assert',
),
);
public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'DateError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
'DateException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
@ -457,99 +365,9 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
'DateMalformedStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
'DateObjectError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
'DateRangeError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'Override' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/Override.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'SQLite3Exception' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
'Safe\\DateTime' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/DateTime.php',
'Safe\\DateTimeImmutable' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/DateTimeImmutable.php',
'Safe\\Exceptions\\ApacheException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ApacheException.php',
'Safe\\Exceptions\\ApcException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/ApcException.php',
'Safe\\Exceptions\\ApcuException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ApcuException.php',
'Safe\\Exceptions\\ArrayException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ArrayException.php',
'Safe\\Exceptions\\Bzip2Exception' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/Bzip2Exception.php',
'Safe\\Exceptions\\CalendarException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/CalendarException.php',
'Safe\\Exceptions\\ClassobjException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ClassobjException.php',
'Safe\\Exceptions\\ComException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ComException.php',
'Safe\\Exceptions\\CubridException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/CubridException.php',
'Safe\\Exceptions\\CurlException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/CurlException.php',
'Safe\\Exceptions\\DatetimeException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/DatetimeException.php',
'Safe\\Exceptions\\DirException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/DirException.php',
'Safe\\Exceptions\\EioException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/EioException.php',
'Safe\\Exceptions\\ErrorfuncException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ErrorfuncException.php',
'Safe\\Exceptions\\ExecException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ExecException.php',
'Safe\\Exceptions\\FileinfoException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FileinfoException.php',
'Safe\\Exceptions\\FilesystemException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FilesystemException.php',
'Safe\\Exceptions\\FilterException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FilterException.php',
'Safe\\Exceptions\\FpmException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FpmException.php',
'Safe\\Exceptions\\FtpException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FtpException.php',
'Safe\\Exceptions\\FunchandException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/FunchandException.php',
'Safe\\Exceptions\\GettextException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/GettextException.php',
'Safe\\Exceptions\\GmpException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/GmpException.php',
'Safe\\Exceptions\\GnupgException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/GnupgException.php',
'Safe\\Exceptions\\HashException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/HashException.php',
'Safe\\Exceptions\\IbaseException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/IbaseException.php',
'Safe\\Exceptions\\IbmDb2Exception' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/IbmDb2Exception.php',
'Safe\\Exceptions\\IconvException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/IconvException.php',
'Safe\\Exceptions\\ImageException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ImageException.php',
'Safe\\Exceptions\\ImapException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ImapException.php',
'Safe\\Exceptions\\InfoException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/InfoException.php',
'Safe\\Exceptions\\InotifyException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/InotifyException.php',
'Safe\\Exceptions\\JsonException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/JsonException.php',
'Safe\\Exceptions\\LdapException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/LdapException.php',
'Safe\\Exceptions\\LibeventException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/LibeventException.php',
'Safe\\Exceptions\\LibxmlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/LibxmlException.php',
'Safe\\Exceptions\\LzfException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/LzfException.php',
'Safe\\Exceptions\\MailparseException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MailparseException.php',
'Safe\\Exceptions\\MbstringException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MbstringException.php',
'Safe\\Exceptions\\MiscException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MiscException.php',
'Safe\\Exceptions\\MssqlException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/MssqlException.php',
'Safe\\Exceptions\\MysqlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MysqlException.php',
'Safe\\Exceptions\\MysqliException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/MysqliException.php',
'Safe\\Exceptions\\NetworkException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/NetworkException.php',
'Safe\\Exceptions\\Oci8Exception' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/Oci8Exception.php',
'Safe\\Exceptions\\OpcacheException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/OpcacheException.php',
'Safe\\Exceptions\\OpensslException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/OpensslException.php',
'Safe\\Exceptions\\OutcontrolException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/OutcontrolException.php',
'Safe\\Exceptions\\PasswordException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/PasswordException.php',
'Safe\\Exceptions\\PcntlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PcntlException.php',
'Safe\\Exceptions\\PcreException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/PcreException.php',
'Safe\\Exceptions\\PgsqlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PgsqlException.php',
'Safe\\Exceptions\\PosixException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PosixException.php',
'Safe\\Exceptions\\PsException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PsException.php',
'Safe\\Exceptions\\PspellException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PspellException.php',
'Safe\\Exceptions\\ReadlineException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ReadlineException.php',
'Safe\\Exceptions\\RpminfoException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/RpminfoException.php',
'Safe\\Exceptions\\RrdException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/RrdException.php',
'Safe\\Exceptions\\SafeExceptionInterface' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php',
'Safe\\Exceptions\\SemException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SemException.php',
'Safe\\Exceptions\\SessionException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SessionException.php',
'Safe\\Exceptions\\ShmopException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ShmopException.php',
'Safe\\Exceptions\\SimplexmlException' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/Exceptions/SimplexmlException.php',
'Safe\\Exceptions\\SocketsException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SocketsException.php',
'Safe\\Exceptions\\SodiumException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SodiumException.php',
'Safe\\Exceptions\\SolrException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SolrException.php',
'Safe\\Exceptions\\SplException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SplException.php',
'Safe\\Exceptions\\SqlsrvException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SqlsrvException.php',
'Safe\\Exceptions\\SsdeepException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SsdeepException.php',
'Safe\\Exceptions\\Ssh2Exception' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/Ssh2Exception.php',
'Safe\\Exceptions\\StatsException' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/Exceptions/StatsException.php',
'Safe\\Exceptions\\StreamException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/StreamException.php',
'Safe\\Exceptions\\StringsException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/StringsException.php',
'Safe\\Exceptions\\SwooleException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/SwooleException.php',
'Safe\\Exceptions\\UodbcException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/UodbcException.php',
'Safe\\Exceptions\\UopzException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/UopzException.php',
'Safe\\Exceptions\\UrlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/UrlException.php',
'Safe\\Exceptions\\VarException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/VarException.php',
'Safe\\Exceptions\\XdiffException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/XdiffException.php',
'Safe\\Exceptions\\XmlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/XmlException.php',
'Safe\\Exceptions\\XmlrpcException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/XmlrpcException.php',
'Safe\\Exceptions\\YamlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/YamlException.php',
'Safe\\Exceptions\\YazException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/YazException.php',
'Safe\\Exceptions\\ZipException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ZipException.php',
'Safe\\Exceptions\\ZlibException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/ZlibException.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
public static function getInitializer(ClassLoader $loader)

File diff suppressed because it is too large Load diff

View file

@ -10,19 +10,10 @@
'dev' => true,
),
'versions' => array(
'beberlei/assert' => array(
'pretty_version' => 'v3.3.3',
'version' => '3.3.3.0',
'reference' => 'b5fd8eacd8915a1b627b8bfc027803f1939734dd',
'type' => 'library',
'install_path' => __DIR__ . '/../beberlei/assert',
'aliases' => array(),
'dev_requirement' => false,
),
'brick/math' => array(
'pretty_version' => '0.9.3',
'version' => '0.9.3.0',
'reference' => 'ca57d18f028f84f777b2168cd1911b0dee2343ae',
'pretty_version' => '0.12.3',
'version' => '0.12.3.0',
'reference' => '866551da34e9a618e64a819ee1e01c20d8a588ba',
'type' => 'library',
'install_path' => __DIR__ . '/../brick/math',
'aliases' => array(),
@ -47,9 +38,9 @@
'dev_requirement' => false,
),
'doctrine/inflector' => array(
'pretty_version' => '2.0.10',
'version' => '2.0.10.0',
'reference' => '5817d0659c5b50c9b950feb9af7b9668e2c436bc',
'pretty_version' => '1.4.4',
'version' => '1.4.4.0',
'reference' => '4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9',
'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/inflector',
'aliases' => array(),
@ -65,9 +56,9 @@
'dev_requirement' => false,
),
'facile-it/php-jose-verifier' => array(
'pretty_version' => '0.3.0',
'version' => '0.3.0.0',
'reference' => 'b6a3d17896dec0c3e383c0ae83b7be855b8fd247',
'pretty_version' => '0.4.5',
'version' => '0.4.5.0',
'reference' => 'fe7e092f90ad2a624e69ae989a781258805d9ed0',
'type' => 'library',
'install_path' => __DIR__ . '/../facile-it/php-jose-verifier',
'aliases' => array(),
@ -82,19 +73,10 @@
'aliases' => array(),
'dev_requirement' => false,
),
'fgrosse/phpasn1' => array(
'pretty_version' => 'v2.5.0',
'version' => '2.5.0.0',
'reference' => '42060ed45344789fb9f21f9f1864fc47b9e3507b',
'type' => 'library',
'install_path' => __DIR__ . '/../fgrosse/phpasn1',
'aliases' => array(),
'dev_requirement' => false,
),
'firebase/php-jwt' => array(
'pretty_version' => 'v6.10.2',
'version' => '6.10.2.0',
'reference' => '30c19ed0f3264cb660ea496895cfb6ef7ee3653b',
'pretty_version' => 'v6.11.0',
'version' => '6.11.0.0',
'reference' => '8f718f4dfc9c5d5f0c994cdfd103921b43592712',
'type' => 'library',
'install_path' => __DIR__ . '/../firebase/php-jwt',
'aliases' => array(),
@ -118,60 +100,42 @@
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/collections' => array(
'pretty_version' => 'v10.48.25',
'version' => '10.48.25.0',
'reference' => '48de3d6bc6aa779112ddcb608a3a96fc975d89d8',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/collections',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/conditionable' => array(
'pretty_version' => 'v10.48.25',
'version' => '10.48.25.0',
'reference' => '3ee34ac306fafc2a6f19cd7cd68c9af389e432a5',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/conditionable',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/contracts' => array(
'pretty_version' => 'v10.48.25',
'version' => '10.48.25.0',
'reference' => 'f90663a69f926105a70b78060a31f3c64e2d1c74',
'pretty_version' => 'v5.4.36',
'version' => '5.4.36.0',
'reference' => '67f642e018f3e95fb0b2ebffc206c3200391b1ab',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/macroable' => array(
'pretty_version' => 'v10.48.25',
'version' => '10.48.25.0',
'reference' => 'dff667a46ac37b634dcf68909d9d41e94dc97c27',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/macroable',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/pagination' => array(
'pretty_version' => 'v10.48.25',
'version' => '10.48.25.0',
'reference' => '616874b9607ff35925347e1710a8b5151858cdf2',
'pretty_version' => 'v5.4.36',
'version' => '5.4.36.0',
'reference' => 'ae1540acf02c8b642666d6901c18d2deb5606b47',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/pagination',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/support' => array(
'pretty_version' => 'v10.48.25',
'version' => '10.48.25.0',
'reference' => '64b258f80175c658aef9e22dd3f2ba18c99b243c',
'pretty_version' => 'v5.4.36',
'version' => '5.4.36.0',
'reference' => 'feab1d1495fd6d38970bd6c83586ba2ace8f299a',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/support',
'aliases' => array(),
'dev_requirement' => false,
),
'lcobucci/clock' => array(
'pretty_version' => '3.0.0',
'version' => '3.0.0.0',
'reference' => '039ef98c6b57b101d10bd11d8fdfda12cbd996dc',
'type' => 'library',
'install_path' => __DIR__ . '/../lcobucci/clock',
'aliases' => array(),
'dev_requirement' => false,
),
'ldap-account-manager/ldap-account-manager' => array(
'pretty_version' => '9.1',
'version' => '9.1.0.0',
@ -191,18 +155,18 @@
'dev_requirement' => false,
),
'nesbot/carbon' => array(
'pretty_version' => '2.72.6',
'version' => '2.72.6.0',
'reference' => '1e9d50601e7035a4c61441a208cb5bed73e108c5',
'pretty_version' => '3.8.6',
'version' => '3.8.6.0',
'reference' => 'ff2f20cf83bd4d503720632ce8a426dc747bf7fd',
'type' => 'library',
'install_path' => __DIR__ . '/../nesbot/carbon',
'aliases' => array(),
'dev_requirement' => false,
),
'paragonie/constant_time_encoding' => array(
'pretty_version' => 'v2.7.0',
'version' => '2.7.0.0',
'reference' => '52a0d99e69f56b9ec27ace92ba56897fe6993105',
'pretty_version' => 'v3.0.0',
'version' => '3.0.0.0',
'reference' => 'df1e7fde177501eee2037dd159cf04f5f301a512',
'type' => 'library',
'install_path' => __DIR__ . '/../paragonie/constant_time_encoding',
'aliases' => array(),
@ -217,6 +181,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'paragonie/sodium_compat' => array(
'pretty_version' => 'v2.1.0',
'version' => '2.1.0.0',
'reference' => 'a673d5f310477027cead2e2f2b6db5d8368157cb',
'type' => 'library',
'install_path' => __DIR__ . '/../paragonie/sodium_compat',
'aliases' => array(),
'dev_requirement' => false,
),
'php-http/async-client-implementation' => array(
'dev_requirement' => false,
'provided' => array(
@ -256,6 +229,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'psr/cache' => array(
'pretty_version' => '3.0.0',
'version' => '3.0.0.0',
'reference' => 'aa5030cfa5405eccfdcb1083ce040c2cb8d253bf',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/cache',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/clock' => array(
'pretty_version' => '1.0.0',
'version' => '1.0.0.0',
@ -280,6 +262,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'psr/event-dispatcher' => array(
'pretty_version' => '1.0.0',
'version' => '1.0.0.0',
'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/event-dispatcher',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/http-client' => array(
'pretty_version' => '1.0.3',
'version' => '1.0.3.0',
@ -314,9 +305,9 @@
),
),
'psr/http-message' => array(
'pretty_version' => '1.1',
'version' => '1.1.0.0',
'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba',
'pretty_version' => '2.0',
'version' => '2.0.0.0',
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
@ -360,12 +351,13 @@
'dev_requirement' => false,
'provided' => array(
0 => '3.0.0',
1 => '1.0|2.0|3.0',
),
),
'psr/simple-cache' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
'pretty_version' => '3.0.0',
'version' => '3.0.0.0',
'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/simple-cache',
'aliases' => array(),
@ -398,6 +390,33 @@
'aliases' => array(),
'dev_requirement' => false,
),
'spomky-labs/pki-framework' => array(
'pretty_version' => '1.2.2',
'version' => '1.2.2.0',
'reference' => '5ac374c3e295c8b917208ff41b4d30f76668478c',
'type' => 'library',
'install_path' => __DIR__ . '/../spomky-labs/pki-framework',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/clock' => array(
'pretty_version' => 'v6.4.13',
'version' => '6.4.13.0',
'reference' => 'b2bf55c4dd115003309eafa87ee7df9ed3dde81b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/clock',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/console' => array(
'pretty_version' => 'v6.4.17',
'version' => '6.4.17.0',
'reference' => '799445db3f15768ecc382ac5699e6da0520a0a04',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/deprecation-contracts' => array(
'pretty_version' => 'v3.5.1',
'version' => '3.5.1.0',
@ -440,6 +459,33 @@
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-grapheme' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
'reference' => 'b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
'reference' => '3833d7255cc303546435cb650316bff708a1c75c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
@ -449,15 +495,6 @@
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
'reference' => '60328e362d4c2c802a54fcbf04f9d3fb892b4cf8',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php83' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
@ -494,10 +531,19 @@
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/string' => array(
'pretty_version' => 'v6.4.15',
'version' => '6.4.15.0',
'reference' => '73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/string',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/translation' => array(
'pretty_version' => 'v6.4.13',
'version' => '6.4.13.0',
'reference' => 'bee9bfabfa8b4045a66bf82520e492cddbaffa66',
'pretty_version' => 'v6.4.19',
'version' => '6.4.19.0',
'reference' => '3b9bf9f33997c064885a7bfc126c14b9daa0e00e',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation',
'aliases' => array(),
@ -527,109 +573,88 @@
'aliases' => array(),
'dev_requirement' => false,
),
'thecodingmachine/safe' => array(
'pretty_version' => 'v2.5.0',
'version' => '2.5.0.0',
'reference' => '3115ecd6b4391662b4931daac4eba6b07a2ac1f0',
'type' => 'library',
'install_path' => __DIR__ . '/../thecodingmachine/safe',
'aliases' => array(),
'tightenco/collect' => array(
'dev_requirement' => false,
'replaced' => array(
0 => 'v5.4.36',
),
'voku/portable-ascii' => array(
'pretty_version' => '2.0.3',
'version' => '2.0.3.0',
'reference' => 'b1d923f88091c6bf09699efcd7c8a1b1bfd7351d',
'type' => 'library',
'install_path' => __DIR__ . '/../voku/portable-ascii',
'aliases' => array(),
'dev_requirement' => false,
),
'web-auth/cose-lib' => array(
'pretty_version' => '4.0.13',
'version' => '4.0.13.0',
'reference' => 'fc733974fe12b550b54a94a08e4e184aca0015e5',
'pretty_version' => '4.4.0',
'version' => '4.4.0.0',
'reference' => '2166016e48e0214f4f63320a7758a9386d14c92a',
'type' => 'library',
'install_path' => __DIR__ . '/../web-auth/cose-lib',
'aliases' => array(),
'dev_requirement' => false,
),
'web-auth/metadata-service' => array(
'pretty_version' => 'v4.0.5',
'version' => '4.0.5.0',
'reference' => '2bc26efc09d280f87777c736f404a2d875d6e7c4',
'type' => 'library',
'install_path' => __DIR__ . '/../web-auth/metadata-service',
'aliases' => array(),
'dev_requirement' => false,
),
'web-auth/webauthn-lib' => array(
'pretty_version' => 'v4.0.5',
'version' => '4.0.5.0',
'reference' => '1b02740ab8539f025419380c9e4c41b090c6cf47',
'pretty_version' => '4.9.2',
'version' => '4.9.2.0',
'reference' => '008b25171c27cf4813420d0de31cc059bcc71f1a',
'type' => 'library',
'install_path' => __DIR__ . '/../web-auth/webauthn-lib',
'aliases' => array(),
'dev_requirement' => false,
),
'web-token/jwt-checker' => array(
'pretty_version' => 'v2.2.11',
'version' => '2.2.11.0',
'reference' => '5f31d98155951739e2fae7455e8466ccddd08f50',
'pretty_version' => '3.4.6',
'version' => '3.4.6.0',
'reference' => '973ab960dd1761b00fce24a7cf2ec2a328499a58',
'type' => 'library',
'install_path' => __DIR__ . '/../web-token/jwt-checker',
'aliases' => array(),
'dev_requirement' => false,
),
'web-token/jwt-core' => array(
'pretty_version' => 'v2.2.11',
'version' => '2.2.11.0',
'reference' => '53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678',
'pretty_version' => '3.4.6',
'version' => '3.4.6.0',
'reference' => '0a47aa6096024af3bff8082e47e27219b9889542',
'type' => 'library',
'install_path' => __DIR__ . '/../web-token/jwt-core',
'aliases' => array(),
'dev_requirement' => false,
),
'web-token/jwt-easy' => array(
'pretty_version' => 'v2.2.11',
'version' => '2.2.11.0',
'reference' => '01db23252bb53d4fd36975b55dd58466bab1bb30',
'type' => 'library',
'install_path' => __DIR__ . '/../web-token/jwt-easy',
'aliases' => array(),
'dev_requirement' => false,
),
'web-token/jwt-encryption' => array(
'pretty_version' => 'v2.2.11',
'version' => '2.2.11.0',
'reference' => '3b8d67d7c5c013750703e7c27f1001544407bbb2',
'pretty_version' => '3.4.6',
'version' => '3.4.6.0',
'reference' => '3e4b1c4080a77a6e97b62b33562805c1fc552b5e',
'type' => 'library',
'install_path' => __DIR__ . '/../web-token/jwt-encryption',
'aliases' => array(),
'dev_requirement' => false,
),
'web-token/jwt-key-mgmt' => array(
'pretty_version' => 'v2.2.11',
'version' => '2.2.11.0',
'reference' => '0b116379515700d237b4e5de86879078ccb09d8a',
'pretty_version' => '3.4.6',
'version' => '3.4.6.0',
'reference' => '4d2a5a1a86477dd50b89aff76962816ddbd64590',
'type' => 'library',
'install_path' => __DIR__ . '/../web-token/jwt-key-mgmt',
'aliases' => array(),
'dev_requirement' => false,
),
'web-token/jwt-library' => array(
'pretty_version' => '3.4.7',
'version' => '3.4.7.0',
'reference' => '1a25c8ced3e2b3c31d32dcfad215cbd8cb812f28',
'type' => 'library',
'install_path' => __DIR__ . '/../web-token/jwt-library',
'aliases' => array(),
'dev_requirement' => false,
),
'web-token/jwt-signature' => array(
'pretty_version' => 'v2.2.11',
'version' => '2.2.11.0',
'reference' => '015b59aaf3b6e8fb9f5bd1338845b7464c7d8103',
'pretty_version' => '3.4.6',
'version' => '3.4.6.0',
'reference' => 'eccfd59e658d4118414cf6d14229aa52eec387e7',
'type' => 'library',
'install_path' => __DIR__ . '/../web-token/jwt-signature',
'aliases' => array(),
'dev_requirement' => false,
),
'web-token/jwt-signature-algorithm-rsa' => array(
'pretty_version' => 'v2.2.11',
'version' => '2.2.11.0',
'reference' => '513ad90eb5ef1886ff176727a769bda4618141b0',
'pretty_version' => '3.4.6',
'version' => '3.4.6.0',
'reference' => '4408e41671294f0390731e2f84065a03a8089ace',
'type' => 'library',
'install_path' => __DIR__ . '/../web-token/jwt-signature-algorithm-rsa',
'aliases' => array(),

View file

@ -3,5 +3,6 @@
Doctrine Inflector is a small library that can perform string manipulations
with regard to uppercase/lowercase and singular/plural forms of words.
[![Build Status](https://github.com/doctrine/inflector/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/inflector/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.0.x)
[![Code Coverage](https://codecov.io/gh/doctrine/inflector/branch/2.0.x/graph/badge.svg)](https://codecov.io/gh/doctrine/inflector/branch/2.0.x)
[![Build Status](https://travis-ci.org/doctrine/inflector.svg)](https://travis-ci.org/doctrine/inflector)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/doctrine/inflector/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/doctrine/inflector/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/doctrine/inflector/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/doctrine/inflector/?branch=master)

View file

@ -13,29 +13,30 @@
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": "^7.2 || ^8.0"
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^11.0",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-strict-rules": "^1.3",
"phpunit/phpunit": "^8.5 || ^9.5",
"vimeo/psalm": "^4.25 || ^5.4"
"doctrine/coding-standard": "^8.0",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpstan/phpstan-strict-rules": "^0.12",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector",
"Doctrine\\Inflector\\": "lib/Doctrine/Inflector"
}
},
"autoload-dev": {
"psr-4": {
"Doctrine\\Tests\\Common\\Inflector\\": "tests/Doctrine/Tests/Common/Inflector",
"Doctrine\\Tests\\Inflector\\": "tests/Doctrine/Tests/Inflector"
}
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
}
}

View file

@ -213,7 +213,8 @@ You can unaccent a string of text using the ``unaccent()`` method:
Legacy API
==========
The API present in Inflector 1.x is still available, but will be deprecated in a future release and dropped for 3.0.
As of 1.4.0, the API present in Inflector 1.x has been marked as deprecated. In the 2.x release series,
the legacy API has been dropped completely.
Support for languages other than English is available in the 2.0 API only.
Acknowledgements

View file

@ -0,0 +1,284 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Common\Inflector;
use Doctrine\Inflector\Inflector as InflectorObject;
use Doctrine\Inflector\InflectorFactory;
use Doctrine\Inflector\LanguageInflectorFactory;
use Doctrine\Inflector\Rules\Pattern;
use Doctrine\Inflector\Rules\Patterns;
use Doctrine\Inflector\Rules\Ruleset;
use Doctrine\Inflector\Rules\Substitution;
use Doctrine\Inflector\Rules\Substitutions;
use Doctrine\Inflector\Rules\Transformation;
use Doctrine\Inflector\Rules\Transformations;
use Doctrine\Inflector\Rules\Word;
use InvalidArgumentException;
use function array_keys;
use function array_map;
use function array_unshift;
use function array_values;
use function sprintf;
use function trigger_error;
use const E_USER_DEPRECATED;
/**
* @deprecated
*/
class Inflector
{
/**
* @var LanguageInflectorFactory|null
*/
private static $factory;
/** @var InflectorObject|null */
private static $instance;
private static function getInstance() : InflectorObject
{
if (self::$factory === null) {
self::$factory = self::createFactory();
}
if (self::$instance === null) {
self::$instance = self::$factory->build();
}
return self::$instance;
}
private static function createFactory() : LanguageInflectorFactory
{
return InflectorFactory::create();
}
/**
* Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'.
*
* @deprecated
*/
public static function tableize(string $word) : string
{
@trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED);
return self::getInstance()->tableize($word);
}
/**
* Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'.
*/
public static function classify(string $word) : string
{
@trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED);
return self::getInstance()->classify($word);
}
/**
* Camelizes a word. This uses the classify() method and turns the first character to lowercase.
*
* @deprecated
*/
public static function camelize(string $word) : string
{
@trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED);
return self::getInstance()->camelize($word);
}
/**
* Uppercases words with configurable delimiters between words.
*
* Takes a string and capitalizes all of the words, like PHP's built-in
* ucwords function. This extends that behavior, however, by allowing the
* word delimiters to be configured, rather than only separating on
* whitespace.
*
* Here is an example:
* <code>
* <?php
* $string = 'top-o-the-morning to all_of_you!';
* echo \Doctrine\Common\Inflector\Inflector::ucwords($string);
* // Top-O-The-Morning To All_of_you!
*
* echo \Doctrine\Common\Inflector\Inflector::ucwords($string, '-_ ');
* // Top-O-The-Morning To All_Of_You!
* ?>
* </code>
*
* @param string $string The string to operate on.
* @param string $delimiters A list of word separators.
*
* @return string The string with all delimiter-separated words capitalized.
*
* @deprecated
*/
public static function ucwords(string $string, string $delimiters = " \n\t\r\0\x0B-") : string
{
@trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please use the "ucwords" function instead.', __METHOD__), E_USER_DEPRECATED);
return ucwords($string, $delimiters);
}
/**
* Clears Inflectors inflected value caches, and resets the inflection
* rules to the initial values.
*
* @deprecated
*/
public static function reset() : void
{
@trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED);
self::$factory = null;
self::$instance = null;
}
/**
* Adds custom inflection $rules, of either 'plural' or 'singular' $type.
*
* ### Usage:
*
* {{{
* Inflector::rules('plural', array('/^(inflect)or$/i' => '\1ables'));
* Inflector::rules('plural', array(
* 'rules' => array('/^(inflect)ors$/i' => '\1ables'),
* 'uninflected' => array('dontinflectme'),
* 'irregular' => array('red' => 'redlings')
* ));
* }}}
*
* @param string $type The type of inflection, either 'plural' or 'singular'
* @param array<string,mixed>|iterable<string,mixed> $rules An array of rules to be added.
* @param boolean $reset If true, will unset default inflections for all
* new rules that are being defined in $rules.
*
* @return void
*
* @deprecated
*/
public static function rules(string $type, iterable $rules, bool $reset = false) : void
{
@trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED);
if (self::$factory === null) {
self::$factory = self::createFactory();
}
self::$instance = null;
switch ($type) {
case 'singular':
self::$factory->withSingularRules(self::buildRuleset($rules), $reset);
break;
case 'plural':
self::$factory->withPluralRules(self::buildRuleset($rules), $reset);
break;
default:
throw new InvalidArgumentException(sprintf('Cannot define custom inflection rules for type "%s".', $type));
}
}
/**
* @param array<string,mixed>|iterable<string,mixed> $rules An array of rules to be added.
*/
private static function buildRuleset(iterable $rules) : Ruleset
{
$regular = [];
$irregular = [];
$uninflected = [];
foreach ($rules as $rule => $pattern) {
if ( ! is_array($pattern)) {
$regular[$rule] = $pattern;
continue;
}
switch ($rule) {
case 'uninflected':
$uninflected = $pattern;
break;
case 'irregular':
$irregular = $pattern;
break;
case 'rules':
$regular = $pattern;
break;
}
}
return new Ruleset(
new Transformations(...array_map(
static function (string $pattern, string $replacement) : Transformation {
return new Transformation(new Pattern($pattern), $replacement);
},
array_keys($regular),
array_values($regular)
)),
new Patterns(...array_map(
static function (string $pattern) : Pattern {
return new Pattern($pattern);
},
$uninflected
)),
new Substitutions(...array_map(
static function (string $word, string $to) : Substitution {
return new Substitution(new Word($word), new Word($to));
},
array_keys($irregular),
array_values($irregular)
))
);
}
/**
* Returns a word in plural form.
*
* @param string $word The word in singular form.
*
* @return string The word in plural form.
*
* @deprecated
*/
public static function pluralize(string $word) : string
{
@trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED);
return self::getInstance()->pluralize($word);
}
/**
* Returns a word in singular form.
*
* @param string $word The word in plural form.
*
* @return string The word in singular form.
*
* @deprecated
*/
public static function singularize(string $word) : string
{
@trigger_error(sprintf('The "%s" method is deprecated and will be dropped in doctrine/inflector 2.0. Please update to the new Inflector API.', __METHOD__), E_USER_DEPRECATED);
return self::getInstance()->singularize($word);
}
}

View file

@ -11,7 +11,9 @@ use Doctrine\Inflector\Rules\Word;
class Inflectible
{
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getSingular(): iterable
{
yield new Transformation(new Pattern('(s)tatuses$'), '\1\2tatus');
@ -47,19 +49,19 @@ class Inflectible
yield new Transformation(new Pattern('(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$'), '\1\2sis');
yield new Transformation(new Pattern('(tax)a$'), '\1on');
yield new Transformation(new Pattern('(c)riteria$'), '\1riterion');
yield new Transformation(new Pattern('([ti])a(?<!regatta)$'), '\1um');
yield new Transformation(new Pattern('([ti])a$'), '\1um');
yield new Transformation(new Pattern('(p)eople$'), '\1\2erson');
yield new Transformation(new Pattern('(m)en$'), '\1an');
yield new Transformation(new Pattern('(c)hildren$'), '\1\2hild');
yield new Transformation(new Pattern('(f)eet$'), '\1oot');
yield new Transformation(new Pattern('(n)ews$'), '\1\2ews');
yield new Transformation(new Pattern('eaus$'), 'eau');
yield new Transformation(new Pattern('^tights$'), 'tights');
yield new Transformation(new Pattern('^shorts$'), 'shorts');
yield new Transformation(new Pattern('s$'), '');
}
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getPlural(): iterable
{
yield new Transformation(new Pattern('(s)tatus$'), '\1\2tatuses');
@ -89,23 +91,21 @@ class Inflectible
yield new Transformation(new Pattern('$'), 's');
}
/** @return Substitution[] */
/**
* @return Substitution[]
*/
public static function getIrregular(): iterable
{
yield new Substitution(new Word('atlas'), new Word('atlases'));
yield new Substitution(new Word('axis'), new Word('axes'));
yield new Substitution(new Word('axe'), new Word('axes'));
yield new Substitution(new Word('beef'), new Word('beefs'));
yield new Substitution(new Word('blouse'), new Word('blouses'));
yield new Substitution(new Word('brother'), new Word('brothers'));
yield new Substitution(new Word('cafe'), new Word('cafes'));
yield new Substitution(new Word('cave'), new Word('caves'));
yield new Substitution(new Word('chateau'), new Word('chateaux'));
yield new Substitution(new Word('niveau'), new Word('niveaux'));
yield new Substitution(new Word('child'), new Word('children'));
yield new Substitution(new Word('canvas'), new Word('canvases'));
yield new Substitution(new Word('cookie'), new Word('cookies'));
yield new Substitution(new Word('brownie'), new Word('brownies'));
yield new Substitution(new Word('corpus'), new Word('corpuses'));
yield new Substitution(new Word('cow'), new Word('cows'));
yield new Substitution(new Word('criterion'), new Word('criteria'));
@ -113,7 +113,6 @@ class Inflectible
yield new Substitution(new Word('demo'), new Word('demos'));
yield new Substitution(new Word('domino'), new Word('dominoes'));
yield new Substitution(new Word('echo'), new Word('echoes'));
yield new Substitution(new Word('epoch'), new Word('epochs'));
yield new Substitution(new Word('foot'), new Word('feet'));
yield new Substitution(new Word('fungus'), new Word('fungi'));
yield new Substitution(new Word('ganglion'), new Word('ganglions'));
@ -152,7 +151,6 @@ class Inflectible
yield new Substitution(new Word('runner-up'), new Word('runners-up'));
yield new Substitution(new Word('safe'), new Word('safes'));
yield new Substitution(new Word('sex'), new Word('sexes'));
yield new Substitution(new Word('sieve'), new Word('sieves'));
yield new Substitution(new Word('soliloquy'), new Word('soliloquies'));
yield new Substitution(new Word('son-in-law'), new Word('sons-in-law'));
yield new Substitution(new Word('syllabus'), new Word('syllabi'));

View file

@ -8,7 +8,9 @@ use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getSingular(): iterable
{
yield from self::getDefault();
@ -28,7 +30,9 @@ final class Uninflected
yield new Pattern('utopia');
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getPlural(): iterable
{
yield from self::getDefault();
@ -39,7 +43,9 @@ final class Uninflected
yield new Pattern('media');
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
private static function getDefault(): iterable
{
yield new Pattern('\w+media');
@ -58,7 +64,6 @@ final class Uninflected
yield new Pattern('butter');
yield new Pattern('cantus');
yield new Pattern('carp');
yield new Pattern('cattle');
yield new Pattern('chassis');
yield new Pattern('clippers');
yield new Pattern('clothing');
@ -106,7 +111,6 @@ final class Uninflected
yield new Pattern('jackanapes');
yield new Pattern('jeans');
yield new Pattern('jedi');
yield new Pattern('kin');
yield new Pattern('kiplingese');
yield new Pattern('knowledge');
yield new Pattern('kongoese');

View file

@ -11,7 +11,9 @@ use Doctrine\Inflector\Rules\Word;
class Inflectible
{
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getSingular(): iterable
{
yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)aux$/'), '\1ail');
@ -21,20 +23,23 @@ class Inflectible
yield new Transformation(new Pattern('/s$/'), '');
}
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getPlural(): iterable
{
yield new Transformation(new Pattern('/(s|x|z)$/'), '\1');
yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/'), '\1aux');
yield new Transformation(new Pattern('/ail$/'), 'ails');
yield new Transformation(new Pattern('/(chacal|carnaval|festival|récital)$/'), '\1s');
yield new Transformation(new Pattern('/al$/'), 'aux');
yield new Transformation(new Pattern('/(bleu|émeu|landau|pneu|sarrau)$/'), '\1s');
yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|lieu|pou|au|eu|eau)$/'), '\1x');
yield new Transformation(new Pattern('/(bleu|émeu|landau|lieu|pneu|sarrau)$/'), '\1s');
yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)$/'), '\1x');
yield new Transformation(new Pattern('/$/'), 's');
}
/** @return Substitution[] */
/**
* @return Substitution[]
*/
public static function getIrregular(): iterable
{
yield new Substitution(new Word('monsieur'), new Word('messieurs'));

View file

@ -8,19 +8,25 @@ use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
private static function getDefault(): iterable
{
yield new Pattern('');

View file

@ -11,14 +11,18 @@ use Doctrine\Inflector\Rules\Word;
class Inflectible
{
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getSingular(): iterable
{
yield new Transformation(new Pattern('/re$/i'), 'r');
yield new Transformation(new Pattern('/er$/i'), '');
}
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getPlural(): iterable
{
yield new Transformation(new Pattern('/e$/i'), 'er');
@ -26,7 +30,9 @@ class Inflectible
yield new Transformation(new Pattern('/$/'), 'er');
}
/** @return Substitution[] */
/**
* @return Substitution[]
*/
public static function getIrregular(): iterable
{
yield new Substitution(new Word('konto'), new Word('konti'));

View file

@ -8,19 +8,25 @@ use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
private static function getDefault(): iterable
{
yield new Pattern('barn');

View file

@ -11,7 +11,9 @@ use Doctrine\Inflector\Rules\Word;
class Inflectible
{
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getSingular(): iterable
{
yield new Transformation(new Pattern('/^(g|)ases$/i'), '\1ás');
@ -32,7 +34,9 @@ class Inflectible
yield new Transformation(new Pattern('/([^ê])s$/i'), '\1');
}
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getPlural(): iterable
{
yield new Transformation(new Pattern('/^(alem|c|p)ao$/i'), '\1aes');
@ -54,7 +58,9 @@ class Inflectible
yield new Transformation(new Pattern('/$/'), 's');
}
/** @return Substitution[] */
/**
* @return Substitution[]
*/
public static function getIrregular(): iterable
{
yield new Substitution(new Word('abdomen'), new Word('abdomens'));

View file

@ -8,19 +8,25 @@ use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
private static function getDefault(): iterable
{
yield new Pattern('tórax');

View file

@ -11,7 +11,9 @@ use Doctrine\Inflector\Rules\Word;
class Inflectible
{
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getSingular(): iterable
{
yield new Transformation(new Pattern('/ereses$/'), 'erés');
@ -21,7 +23,9 @@ class Inflectible
yield new Transformation(new Pattern('/s$/'), '');
}
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getPlural(): iterable
{
yield new Transformation(new Pattern('/ú([sn])$/i'), 'u\1es');
@ -35,7 +39,9 @@ class Inflectible
yield new Transformation(new Pattern('/$/'), 's');
}
/** @return Substitution[] */
/**
* @return Substitution[]
*/
public static function getIrregular(): iterable
{
yield new Substitution(new Word('el'), new Word('los'));

View file

@ -8,19 +8,25 @@ use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
private static function getDefault(): iterable
{
yield new Pattern('lunes');

View file

@ -11,20 +11,26 @@ use Doctrine\Inflector\Rules\Word;
class Inflectible
{
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getSingular(): iterable
{
yield new Transformation(new Pattern('/l[ae]r$/i'), '');
}
/** @return Transformation[] */
/**
* @return Transformation[]
*/
public static function getPlural(): iterable
{
yield new Transformation(new Pattern('/([eöiü][^aoıueöiü]{0,6})$/u'), '\1ler');
yield new Transformation(new Pattern('/([aoıu][^aoıueöiü]{0,6})$/u'), '\1lar');
}
/** @return Substitution[] */
/**
* @return Substitution[]
*/
public static function getIrregular(): iterable
{
yield new Substitution(new Word('ben'), new Word('biz'));

View file

@ -8,19 +8,25 @@ use Doctrine\Inflector\Rules\Pattern;
final class Uninflected
{
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getSingular(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
public static function getPlural(): iterable
{
yield from self::getDefault();
}
/** @return Pattern[] */
/**
* @return Pattern[]
*/
private static function getDefault(): iterable
{
yield new Pattern('lunes');

View file

@ -0,0 +1,13 @@
includes:
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
parameters:
level: 7
paths:
- lib
- tests
excludes_analyse:
- %rootDir%/../../../tests/Doctrine/Tests/Common/*

View file

@ -1,4 +1,4 @@
/vendor/
/.phpunit.result.cache
/.php_cs.cache
/.php-cs-fixer.cache
/composer.lock

View file

@ -0,0 +1,60 @@
<?php
/*
* Additional rules or rules to override.
* These rules will be added to default rules or will override them if the same key already exists.
*/
$additionalRules = [
'visibility_required' => true,
'heredoc_indentation' => true,
'heredoc_to_nowdoc' => true,
'no_null_property_initialization' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'global_namespace_import' => [
'import_classes' => true,
'import_constants' => true,
'import_functions' => true,
],
'constant_case' => true,
'declare_strict_types' => true,
'indentation_type' => true,
'no_superfluous_phpdoc_tags' => [
'allow_mixed' => true,
],
'phpdoc_line_span' => [
'const' => 'single',
'method' => 'multi',
'property' => 'single',
],
'phpdoc_trim_consecutive_blank_line_separation' => true,
// risky rules
'fopen_flag_order' => true,
'fopen_flags' => true,
'ereg_to_preg' => true,
'implode_call' => true,
'no_unset_on_property' => true,
// custom
'comment_to_phpdoc' => true,
'phpdoc_to_comment' => false,
];
$rulesProvider = new Facile\CodingStandards\Rules\CompositeRulesProvider([
new Facile\CodingStandards\Rules\DefaultRulesProvider(),
new Facile\CodingStandards\Rules\ArrayRulesProvider($additionalRules),
]);
$config = new PhpCsFixer\Config();
$config->setRules($rulesProvider->getRules());
$finder = new PhpCsFixer\Finder();
/*
* You can set manually these paths:
*/
$autoloadPathProvider = new Facile\CodingStandards\AutoloadPathProvider();
$finder->in($autoloadPathProvider->getPaths());
$config->setFinder($finder);
return $config;

View file

@ -11,7 +11,11 @@
],
"minimum-stability": "stable",
"config": {
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"facile-it/facile-coding-standard": true,
"php-http/discovery": true
}
},
"keywords": [
"jwt",
@ -31,17 +35,17 @@
"php": "^7.2 || ^8.0",
"ext-json": "*",
"php-http/discovery": "^1.7",
"psr/clock": "^1.0",
"psr/http-client": "^1.0",
"psr/http-message": "^1.0",
"psr/simple-cache": "^1.0",
"psr/http-message": "^1.0 || 2.0",
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0",
"spomky-labs/base64url": "^2.0.1",
"symfony/polyfill-mbstring": "^1.15",
"web-token/jwt-checker": "^2.2.0",
"web-token/jwt-core": "^2.2.0",
"web-token/jwt-easy": "^2.2.0",
"web-token/jwt-key-mgmt": "^2.2.0",
"web-token/jwt-signature": "^2.2.0",
"web-token/jwt-signature-algorithm-rsa": "^2.2.0"
"web-token/jwt-checker": "^2.2.0 || ^3.0",
"web-token/jwt-core": "^2.2.0 || ^3.0",
"web-token/jwt-key-mgmt": "^2.2.0 || ^3.0",
"web-token/jwt-signature": "^2.2.0 || ^3.0",
"web-token/jwt-signature-algorithm-rsa": "^2.2.0 || ^3.0"
},
"autoload": {
"files": [
@ -58,34 +62,35 @@
}
},
"require-dev": {
"facile-it/facile-coding-standard": "^0.4.1",
"friendsofphp/php-cs-fixer": "^2.16.1",
"laminas/laminas-diactoros": "^2.2",
"facile-it/facile-coding-standard": "^0.5",
"friendsofphp/php-cs-fixer": "^3.0",
"laminas/laminas-diactoros": "^2.2 || ^3.0.0",
"php-http/curl-client": "^2.1",
"phpspec/prophecy-phpunit": "^1.1 || ^2.0",
"phpunit/phpunit": "^8.5.14 || ^9.3",
"vimeo/psalm": "^4.4.1",
"web-token/jwt-encryption": "^2.2.0",
"web-token/jwt-encryption-algorithm-aescbc": "^2.2.0",
"web-token/jwt-encryption-algorithm-aesgcm": "^2.2.0",
"web-token/jwt-encryption-algorithm-aesgcmkw": "^2.2.0",
"web-token/jwt-encryption-algorithm-aeskw": "^2.2.0",
"web-token/jwt-encryption-algorithm-dir": "^2.2.0",
"web-token/jwt-encryption-algorithm-ecdh-es": "^2.2.0",
"web-token/jwt-encryption-algorithm-experimental": "^2.2.0",
"web-token/jwt-encryption-algorithm-pbes2": "^2.2.0",
"web-token/jwt-encryption-algorithm-rsa": "^2.2.0",
"web-token/jwt-nested-token": "^2.2.0",
"web-token/jwt-signature-algorithm-ecdsa": "^2.2.0",
"web-token/jwt-signature-algorithm-experimental": "^2.2.0",
"web-token/jwt-signature-algorithm-hmac": "^2.2.0",
"web-token/jwt-signature-algorithm-none": "^2.2.0",
"web-token/jwt-util-ecc": "^2.2.0"
"vimeo/psalm": "^4.30.0 || ^5.13.1",
"web-token/jwt-checker": "^2.2.0 || ^3.2.0",
"web-token/jwt-encryption": "^2.2.0 || ^3.0",
"web-token/jwt-encryption-algorithm-aescbc": "^2.2.0 || ^3.0",
"web-token/jwt-encryption-algorithm-aesgcm": "^2.2.0 || ^3.0",
"web-token/jwt-encryption-algorithm-aesgcmkw": "^2.2.0 || ^3.0",
"web-token/jwt-encryption-algorithm-aeskw": "^2.2.0 || ^3.0",
"web-token/jwt-encryption-algorithm-dir": "^2.2.0 || ^3.0",
"web-token/jwt-encryption-algorithm-ecdh-es": "^2.2.0 || ^3.0",
"web-token/jwt-encryption-algorithm-experimental": "^2.2.0 || ^3.0",
"web-token/jwt-encryption-algorithm-pbes2": "^2.2.0 || ^3.0",
"web-token/jwt-encryption-algorithm-rsa": "^2.2.0 || ^3.0",
"web-token/jwt-nested-token": "^2.2.0 || ^3.0",
"web-token/jwt-signature-algorithm-ecdsa": "^2.2.0 || ^3.0",
"web-token/jwt-signature-algorithm-experimental": "^2.2.0 || ^3.0",
"web-token/jwt-signature-algorithm-hmac": "^2.2.0 || ^3.0",
"web-token/jwt-signature-algorithm-none": "^2.2.0 || ^3.0",
"web-token/jwt-util-ecc": "^2.2.0 || ^3.0"
},
"scripts": {
"cs-check": "php-cs-fixer fix --dry-run --diff --allow-risky=yes",
"cs-fix": "php-cs-fixer fix --diff --allow-risky=yes",
"psalm": "psalm",
"psalm": "psalm --php-version=8.2",
"test": "phpunit",
"test-coverage": "phpunit --coverage-text",
"check": [

View file

@ -4,9 +4,10 @@ declare(strict_types=1);
namespace Facile\JoseVerifier;
use Facile\JoseVerifier\ClaimChecker\AuthTimeChecker;
use Facile\JoseVerifier\ClaimChecker\AzpChecker;
use Facile\JoseVerifier\ClaimChecker\NonceChecker;
use Facile\JoseVerifier\Checker\AuthTimeChecker;
use Facile\JoseVerifier\Checker\AzpChecker;
use Facile\JoseVerifier\Checker\InternalClock;
use Facile\JoseVerifier\Checker\NonceChecker;
use Facile\JoseVerifier\Decrypter\TokenDecrypterInterface;
use Facile\JoseVerifier\Exception\InvalidArgumentException;
use Facile\JoseVerifier\Exception\InvalidTokenException;
@ -15,10 +16,17 @@ use Facile\JoseVerifier\JWK\JwksProviderInterface;
use Facile\JoseVerifier\JWK\MemoryJwksProvider;
use Facile\JoseVerifier\Validate\Validate;
use function is_array;
use Jose\Component\Checker\AlgorithmChecker;
use Jose\Component\Checker\AudienceChecker;
use Jose\Component\Checker\ExpirationTimeChecker;
use Jose\Component\Checker\IssuedAtChecker;
use Jose\Component\Checker\IssuerChecker;
use Jose\Component\Checker\NotBeforeChecker;
use Jose\Component\Core\JWK;
use Jose\Component\Core\JWKSet;
use Jose\Component\Core\Util\JsonConverter;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Psr\Clock\ClockInterface;
use function str_replace;
use function strpos;
use Throwable;
@ -65,12 +73,16 @@ abstract class AbstractTokenVerifier implements TokenVerifierInterface
/** @var TokenDecrypterInterface|null */
protected $decrypter;
public function __construct(string $issuer, string $clientId, ?TokenDecrypterInterface $decrypter = null)
/** @var ClockInterface */
protected $clock;
public function __construct(string $issuer, string $clientId, ?TokenDecrypterInterface $decrypter = null, ?ClockInterface $clock = null)
{
$this->issuer = $issuer;
$this->clientId = $clientId;
$this->jwksProvider = new MemoryJwksProvider();
$this->decrypter = $decrypter;
$this->clock = $clock ?: new InternalClock();
}
/**
@ -181,6 +193,9 @@ abstract class AbstractTokenVerifier implements TokenVerifierInterface
return $this->decrypter->decrypt($jwt) ?? '{}';
}
/**
* @psalm-suppress TooManyArguments
*/
protected function create(string $jwt): Validate
{
$mandatoryClaims = [];
@ -189,38 +204,37 @@ abstract class AbstractTokenVerifier implements TokenVerifierInterface
if ($this->aadIssValidation) {
$payload = $this->getPayload($jwt);
$expectedIssuer = str_replace('{tenantid}', $payload['tid'] ?? '', $expectedIssuer);
$expectedIssuer = str_replace('{tenantid}', (string) ($payload['tid'] ?? ''), $expectedIssuer);
}
$validator = Validate::token($jwt)
->keyset($this->buildJwks($jwt))
->iss($expectedIssuer)
->iat($this->clockTolerance)
->aud($this->clientId)
->exp($this->clockTolerance)
->nbf($this->clockTolerance);
->claim(new IssuerChecker([$expectedIssuer], true))
->claim(new IssuedAtChecker($this->clockTolerance, true, $this->clock))
->claim(new AudienceChecker($this->clientId, true))
->claim(new ExpirationTimeChecker($this->clockTolerance, false, $this->clock))
->claim(new NotBeforeChecker($this->clockTolerance, true, $this->clock));
if (null !== $this->azp) {
$validator = $validator->claim('azp', new AzpChecker($this->azp));
$validator = $validator->claim(new AzpChecker($this->azp));
}
if (null !== $this->expectedAlg) {
$validator = $validator->alg($this->expectedAlg);
$validator = $validator->header(new AlgorithmChecker([$this->expectedAlg], true));
}
if (null !== $this->nonce) {
$validator = $validator->claim('nonce', new NonceChecker($this->nonce));
$validator = $validator->claim(new NonceChecker($this->nonce));
}
if (null !== $this->maxAge) {
$validator = $validator->claim('auth_time', new AuthTimeChecker($this->maxAge, $this->clockTolerance));
$validator = $validator->claim(new AuthTimeChecker($this->maxAge, $this->clockTolerance));
}
if ((int) $this->maxAge > 0 || null !== $this->maxAge) {
$mandatoryClaims[] = 'auth_time';
}
/** @var Validate $validator */
$validator = $validator->mandatory($mandatoryClaims);
return $validator;

View file

@ -13,21 +13,25 @@ use Facile\JoseVerifier\JWK\MemoryJwksProvider;
/**
* @psalm-import-type ClientMetadataObject from Psalm\PsalmTypes
* @psalm-import-type IssuerMetadataObject from Psalm\PsalmTypes
* @psalm-import-type JWKSetObject from Psalm\PsalmTypes
* @psalm-import-type IssuerMetadataObject from TokenVerifierBuilderInterface
*
* @template TVerifier of AbstractTokenVerifier
*
* @template-implements TokenVerifierBuilderInterface<TVerifier>
*/
abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInterface
{
/**
* @var null|array<string, mixed>
*
* @psalm-var null|ClientMetadataObject
*/
protected $clientMetadata;
/**
* @var null|array<string, mixed>
*
* @psalm-var null|IssuerMetadataObject
*/
protected $issuerMetadata;
@ -49,6 +53,7 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter
/**
* @param array<string, mixed> $clientMetadata
*
* @psalm-param ClientMetadataObject $clientMetadata
*/
public function setClientMetadata(array $clientMetadata): void
@ -58,6 +63,7 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter
/**
* @param array<string, mixed> $issuerMetadata
*
* @psalm-param IssuerMetadataObject $issuerMetadata
*/
public function setIssuerMetadata(array $issuerMetadata): void
@ -105,10 +111,11 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter
return $this->clientJwksProvider;
}
/** @var JWKSetObject $jwks */
/** @psalm-var JWKSetObject $jwks */
$jwks = ['keys' => []];
if ($this->clientMetadata) {
/** @psalm-var JWKSetObject $jwks */
$jwks = $this->clientMetadata['jwks'] ?? $jwks;
}
@ -133,6 +140,7 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter
/**
* @return array<string, mixed>
*
* @psalm-return ClientMetadataObject
*/
protected function getClientMetadata(): array
@ -146,6 +154,7 @@ abstract class AbstractTokenVerifierBuilder implements TokenVerifierBuilderInter
/**
* @return array<string, mixed>
*
* @psalm-return IssuerMetadataObject
*/
protected function getIssuerMetadata(): array

View file

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Facile\JoseVerifier\ClaimChecker;
namespace Facile\JoseVerifier\Checker;
use Base64Url\Base64Url;
use function hash;
@ -13,6 +13,9 @@ use function sprintf;
use function strlen;
use function substr;
/**
* @internal
*/
abstract class AbstractHashChecker implements ClaimChecker
{
/** @var string */
@ -45,7 +48,7 @@ abstract class AbstractHashChecker implements ClaimChecker
}
/**
* {@inheritdoc}
* @param mixed $value
*/
public function checkClaim($value): void
{

View file

@ -2,8 +2,11 @@
declare(strict_types=1);
namespace Facile\JoseVerifier\ClaimChecker;
namespace Facile\JoseVerifier\Checker;
/**
* @internal
*/
final class AtHashChecker extends AbstractHashChecker
{
private const CLAIM_NAME = 'at_hash';

View file

@ -2,13 +2,16 @@
declare(strict_types=1);
namespace Facile\JoseVerifier\ClaimChecker;
namespace Facile\JoseVerifier\Checker;
use function is_int;
use Jose\Component\Checker\ClaimChecker;
use Jose\Component\Checker\InvalidClaimException;
use function time;
use Psr\Clock\ClockInterface;
/**
* @internal
*/
final class AuthTimeChecker implements ClaimChecker
{
private const CLAIM_NAME = 'auth_time';
@ -19,14 +22,18 @@ final class AuthTimeChecker implements ClaimChecker
/** @var int */
private $allowedTimeDrift;
public function __construct(int $maxAge, int $allowedTimeDrift = 0)
/** @var ClockInterface */
private $clock;
public function __construct(int $maxAge, int $allowedTimeDrift = 0, ?ClockInterface $clock = null)
{
$this->maxAge = $maxAge;
$this->allowedTimeDrift = $allowedTimeDrift;
$this->clock = $clock ?: new InternalClock();
}
/**
* {@inheritdoc}
* @param mixed $value
*/
public function checkClaim($value): void
{
@ -34,7 +41,7 @@ final class AuthTimeChecker implements ClaimChecker
throw new InvalidClaimException('"auth_time" must be an integer.', self::CLAIM_NAME, $value);
}
if ($value + $this->maxAge < time() - $this->allowedTimeDrift) {
if ($value + $this->maxAge < $this->clock->now()->getTimestamp() - $this->allowedTimeDrift) {
throw new InvalidClaimException('Too much time has elapsed since the last End-User authentication.', self::CLAIM_NAME, $value);
}
}

View file

@ -2,12 +2,15 @@
declare(strict_types=1);
namespace Facile\JoseVerifier\ClaimChecker;
namespace Facile\JoseVerifier\Checker;
use Jose\Component\Checker\ClaimChecker;
use Jose\Component\Checker\InvalidClaimException;
use function sprintf;
/**
* @internal
*/
final class AzpChecker implements ClaimChecker
{
private const CLAIM_NAME = 'azp';
@ -21,7 +24,7 @@ final class AzpChecker implements ClaimChecker
}
/**
* {@inheritdoc}
* @param mixed $value
*/
public function checkClaim($value): void
{

View file

@ -2,8 +2,11 @@
declare(strict_types=1);
namespace Facile\JoseVerifier\ClaimChecker;
namespace Facile\JoseVerifier\Checker;
/**
* @internal
*/
final class CHashChecker extends AbstractHashChecker
{
private const CLAIM_NAME = 'c_hash';

View file

@ -2,34 +2,31 @@
declare(strict_types=1);
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2020 Spomky-Labs
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace Jose\Easy;
namespace Facile\JoseVerifier\Checker;
use Jose\Component\Checker\ClaimChecker;
use Jose\Component\Checker\HeaderChecker;
use Jose\Component\Checker\InvalidClaimException;
use Jose\Component\Checker\InvalidHeaderException;
/**
* @internal
*/
final class CallableChecker implements ClaimChecker, HeaderChecker
{
/**
* @var string
*/
/** @var string */
private $key;
/**
* @var callable
*
* @psalm-var callable(mixed): bool
*/
private $callable;
/**
* @psalm-param callable(mixed): bool $callable
*/
public function __construct(string $key, callable $callable)
{
$this->key = $key;
@ -56,7 +53,7 @@ final class CallableChecker implements ClaimChecker, HeaderChecker
}
/**
* {@inheritdoc}
* @param mixed $value
*/
public function checkHeader($value): void
{

View file

@ -2,38 +2,25 @@
declare(strict_types=1);
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2020 Spomky-Labs
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace Facile\JoseVerifier\Checker;
namespace Jose\Easy;
use function in_array;
use function is_string;
use Jose\Component\Checker\HeaderChecker;
use Jose\Component\Checker\InvalidHeaderException;
/**
* This class is a header parameter checker.
* When the "enc" header parameter is present, it will check if the value is within the allowed ones.
*
* @internal
*/
final class ContentEncryptionAlgorithmChecker implements HeaderChecker
{
private const HEADER_NAME = 'enc';
/**
* @var bool
*/
private $protectedHeader = false;
/** @var bool */
private $protectedHeader;
/**
* @var string[]
*/
/** @var string[] */
private $supportedAlgorithms;
/**
@ -46,7 +33,7 @@ final class ContentEncryptionAlgorithmChecker implements HeaderChecker
}
/**
* {@inheritdoc}
* @param mixed $value
*
* @throws InvalidHeaderException if the header is invalid
*/

View file

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Facile\JoseVerifier\Checker;
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
/**
* @internal
*/
final class InternalClock implements ClockInterface
{
public function now(): DateTimeImmutable
{
return new DateTimeImmutable();
}
}

View file

@ -2,12 +2,15 @@
declare(strict_types=1);
namespace Facile\JoseVerifier\ClaimChecker;
namespace Facile\JoseVerifier\Checker;
use Jose\Component\Checker\ClaimChecker;
use Jose\Component\Checker\InvalidClaimException;
use function sprintf;
/**
* @internal
*/
final class NonceChecker implements ClaimChecker
{
private const CLAIM_NAME = 'nonce';
@ -21,7 +24,7 @@ final class NonceChecker implements ClaimChecker
}
/**
* {@inheritdoc}
* @param mixed $value
*/
public function checkClaim($value): void
{

View file

@ -2,8 +2,11 @@
declare(strict_types=1);
namespace Facile\JoseVerifier\ClaimChecker;
namespace Facile\JoseVerifier\Checker;
/**
* @internal
*/
final class SHashChecker extends AbstractHashChecker
{
private const CLAIM_NAME = 's_hash';

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Facile\JoseVerifier\Decrypter;
use function class_exists;
use Facile\JoseVerifier\Checker\ContentEncryptionAlgorithmChecker;
use Facile\JoseVerifier\Exception\InvalidTokenException;
use Facile\JoseVerifier\Exception\LogicException;
use function Facile\JoseVerifier\jose_secret_key;
@ -24,8 +25,6 @@ use Jose\Component\Encryption\JWELoader;
use Jose\Component\Encryption\JWETokenSupport;
use Jose\Component\Encryption\Serializer\CompactSerializer;
use Jose\Component\Encryption\Serializer\JWESerializerManager;
use Jose\Easy\AlgorithmProvider;
use Jose\Easy\ContentEncryptionAlgorithmChecker;
use function preg_match;
use Throwable;
@ -44,7 +43,7 @@ class TokenDecrypter implements TokenDecrypterInterface
private $clientSecret;
/** @var Algorithm[] */
private $algorithms;
private $algorithms = [];
public function withExpectedAlg(?string $expectedAlg): self
{
@ -81,9 +80,15 @@ class TokenDecrypter implements TokenDecrypterInterface
public function __construct()
{
$this->jwksProvider = new MemoryJwksProvider();
$this->algorithms = (new AlgorithmProvider($this->getAlgorithmMap()))
->getAvailableAlgorithms()
;
foreach ($this->getAlgorithmMap() as $algorithmClass) {
if (class_exists($algorithmClass)) {
try {
$this->algorithms[] = new $algorithmClass();
} catch (Throwable $throwable) {
//does nothing
}
}
}
}
private function buildJwks(string $jwt): JWKSet
@ -145,6 +150,7 @@ class TokenDecrypter implements TokenDecrypterInterface
/**
* @return string[]
*
* @psalm-return list<class-string<Algorithm>>
*/
protected function getAlgorithmMap(): array

View file

@ -4,13 +4,12 @@ declare(strict_types=1);
namespace Facile\JoseVerifier;
use Facile\JoseVerifier\ClaimChecker\AtHashChecker;
use Facile\JoseVerifier\ClaimChecker\CHashChecker;
use Facile\JoseVerifier\ClaimChecker\SHashChecker;
use Facile\JoseVerifier\Checker\AtHashChecker;
use Facile\JoseVerifier\Checker\CHashChecker;
use Facile\JoseVerifier\Checker\SHashChecker;
use Facile\JoseVerifier\Exception\InvalidTokenException;
use InvalidArgumentException;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Jose\Easy\Validate;
use Throwable;
/**
@ -62,6 +61,7 @@ final class IdTokenVerifier extends AbstractTokenVerifier implements IdTokenVeri
/**
* @inheritDoc
*
* @psalm-suppress MixedReturnTypeCoercion
*/
public function verify(string $jwt): array
@ -82,24 +82,21 @@ final class IdTokenVerifier extends AbstractTokenVerifier implements IdTokenVeri
$alg = $header['alg'] ?? null;
if (null !== $this->accessToken) {
$requiredClaims[] = 'at_hash';
$validator = $validator->claim('at_hash', new AtHashChecker($this->accessToken, $alg ?: ''));
$validator = $validator->claim(new AtHashChecker($this->accessToken, $alg ?: ''));
}
if (null !== $this->code) {
$requiredClaims[] = 'c_hash';
$validator = $validator->claim('c_hash', new CHashChecker($this->code, $alg ?: ''));
$validator = $validator->claim(new CHashChecker($this->code, $alg ?: ''));
}
if (null !== $this->state) {
$validator = $validator->claim('s_hash', new SHashChecker($this->state, $alg ?: ''));
$validator = $validator->claim(new SHashChecker($this->state, $alg ?: ''));
}
/** @var Validate $validator */
$validator = $validator->mandatory($requiredClaims);
try {
return $validator->run()->claims->all();
return $validator->run();
} catch (Throwable $e) {
throw $this->processException($e);
}

View file

@ -35,9 +35,6 @@ class CachedJwksProvider implements JwksProviderInterface
$this->ttl = $ttl;
}
/**
* @inheritDoc
*/
public function getJwks(): array
{
/** @var null|string $cached */

View file

@ -20,6 +20,7 @@ class JwksProviderBuilder
{
/**
* @var array|null
*
* @psalm-var null|JWKSetObject
*/
private $jwks;

View file

@ -11,6 +11,7 @@ class MemoryJwksProvider implements JwksProviderInterface
{
/**
* @var array
*
* @psalm-var JWKSetObject
*/
private $jwks;

View file

@ -45,8 +45,6 @@ class RemoteJwksProvider implements JwksProviderInterface
/**
* @param array<string, string|string[]> $headers
*
* @return RemoteJwksProvider
*/
public function withHeaders(array $headers): self
{
@ -88,6 +86,7 @@ class RemoteJwksProvider implements JwksProviderInterface
/**
* @param mixed $data
*
* @psalm-assert-if-true JWKSetObject $data
*/
private function isJWKSet($data): bool

View file

@ -4,24 +4,23 @@ declare(strict_types=1);
namespace Facile\JoseVerifier;
use Jose\Easy\Validate;
use Throwable;
final class JWTVerifier extends AbstractTokenVerifier
{
/**
* @inheritDoc
*
* @psalm-suppress MixedReturnTypeCoercion
*/
public function verify(string $jwt): array
{
$jwt = $this->decrypt($jwt);
/** @var Validate $validator */
$validator = $this->create($jwt)
->mandatory(['iss', 'sub', 'aud', 'exp', 'iat']);
try {
return $validator->run()->claims->all();
return $validator->run();
} catch (Throwable $e) {
throw $this->processException($e);
}

View file

@ -16,6 +16,8 @@ use SimpleXMLElement;
/**
* @internal
*
* @codeCoverageIgnore
*/
final class Plugin implements PluginEntryPointInterface
{
@ -41,7 +43,7 @@ final class Plugin implements PluginEntryPointInterface
{
$dir = new RecursiveDirectoryIterator($folder);
$ite = new RecursiveIteratorIterator($dir);
/** @psalm-var \FilterIterator<array-key, string[]> $files */
/** @psalm-var \Iterator<array-key, string[]> $files */
$files = new RegexIterator($ite, $pattern, RegexIterator::GET_MATCH);
return array_merge([], ...array_values(iterator_to_array($files)));

View file

@ -6,6 +6,7 @@ namespace Facile\JoseVerifier\Psalm;
/**
* @internal
*
* @psalm-type JWKObject = array{kty: "RSA"|"EC"|"oct"|string, use?: "sig"|"enc"|string, key_ops?: list<"sign"|"verify"|"encrypt"|"decrypt"|"wrapKey"|"unwrapKey"|"deriveKey"|"deriveBits"|string>, kid?: string, alg?: string, x5u?: string, x5c?: list<string>, x5t?: string, x5t#S256?: string, crv?: string, x?: string, y?: string, k?: string, n?: string, e?: string, d?: string, p?: string, q?: string, dp?: string, dq?: string, qi?: string}
* @psalm-type JWKSetObject = array{keys: list<JWKObject>}
* @psalm-type OpenIdDisplayType = non-empty-string
@ -16,10 +17,10 @@ namespace Facile\JoseVerifier\Psalm;
* @psalm-type OpenIdApplicationType = "web"|"native"
* @psalm-type OpenIdSubjectType = "pairwise"|"public"
* @psalm-type OpenIdAuthMethod = "client_secret_post"|"client_secret_basic"|"client_secret_jwt"|"private_key_jwt"|"none"|"tls_client_auth"|"self_signed_tls_client_auth"
* @psalm-type ClientMetadataObject = array{client_id: non-empty-string, client_secret?: string, redirect_uris?: list<non-empty-string>, jwks?: JWKSetObject, jwks_uri?: non-empty-string, response_types?: list<OpenIdResponseType>, grant_types?: list<OpenIdGrantType>, application_type?: OpenIdApplicationType, contacts?: list<non-empty-string>, client_name?: string, logo_uri?: non-empty-string, client_uri?: non-empty-string, policy_uri?: non-empty-string, tos_uri?: non-empty-string, sector_identifier_uri?: non-empty-string, subject_type?: OpenIdSubjectType, authorization_signed_response_alg?: non-empty-string, authorization_encrypted_response_alg?: non-empty-string, authorization_encrypted_response_enc?: non-empty-string, id_token_signed_response_alg?: non-empty-string, id_token_encrypted_response_alg?: non-empty-string, id_token_encrypted_response_enc?: non-empty-string, userinfo_signed_response_alg?: non-empty-string, userinfo_encrypted_response_alg?: non-empty-string, userinfo_encrypted_response_enc?: non-empty-string, request_object_signing_alg?: non-empty-string, request_object_encryption_alg?: non-empty-string, request_object_encryption_enc?: non-empty-string, token_endpoint_auth_method?: OpenIdAuthMethod, token_endpoint_auth_signing_alg?: non-empty-string, default_max_age?: int, require_auth_time?: bool, default_acr_values?: list<string>, initiate_login_uri?: non-empty-string, request_uris?: list<non-empty-string>, scope?: string, software_id?: non-empty-string, software_version?: non-empty-string, introspection_endpoint_auth_method?: non-empty-string, revocation_endpoint_auth_method?: non-empty-string}
* @psalm-type ClientMetadataObject = array{client_id: non-empty-string, client_secret?: string, redirect_uris?: list<non-empty-string>, jwks?: JWKSetObject, jwks_uri?: non-empty-string, response_types?: list<OpenIdResponseType>, grant_types?: list<OpenIdGrantType>, application_type?: OpenIdApplicationType, contacts?: list<non-empty-string>, client_name?: string, logo_uri?: non-empty-string, client_uri?: non-empty-string, policy_uri?: non-empty-string, tos_uri?: non-empty-string, sector_identifier_uri?: non-empty-string, subject_type?: OpenIdSubjectType, authorization_signed_response_alg?: non-empty-string, authorization_encrypted_response_alg?: non-empty-string, authorization_encrypted_response_enc?: non-empty-string, id_token_signed_response_alg?: non-empty-string, id_token_encrypted_response_alg?: non-empty-string, id_token_encrypted_response_enc?: non-empty-string, userinfo_signed_response_alg?: non-empty-string, userinfo_encrypted_response_alg?: non-empty-string, userinfo_encrypted_response_enc?: non-empty-string, request_object_signing_alg?: non-empty-string, request_object_encryption_alg?: non-empty-string, request_object_encryption_enc?: non-empty-string, token_endpoint_auth_method?: OpenIdAuthMethod, token_endpoint_auth_signing_alg?: non-empty-string, default_max_age?: int, require_auth_time?: bool, default_acr_values?: list<string>, initiate_login_uri?: non-empty-string, request_uris?: list<non-empty-string>, scope?: string, software_id?: non-empty-string, software_version?: non-empty-string, introspection_endpoint_auth_method?: non-empty-string, revocation_endpoint_auth_method?: non-empty-string}&array<string, mixed>
* @psalm-type IssuerMetadataObject = array{issuer: non-empty-string, authorization_endpoint: non-empty-string, token_endpoint?: non-empty-string, userinfo_endpoint?: non-empty-string, jwks_uri: non-empty-string, registration_endpoint?: non-empty-string, scopes_supported?: list<non-empty-string>, response_types_supported: non-empty-list<OpenIdResponseType>, response_modes_supported?: list<OpenIdResponseMode>, grant_types_supported?: list<OpenIdGrantType>, acr_values_supported?: list<non-empty-string>, subject_types_supported?: list<OpenIdSubjectType>, id_token_signing_alg_values_supported: non-empty-list<non-empty-string>, id_token_encryption_alg_values_supported?: list<non-empty-string>, id_token_encryption_enc_values_supported?: list<non-empty-string>, userinfo_signing_alg_values_supported?: list<non-empty-string>, userinfo_encryption_alg_values_supported?: list<non-empty-string>, userinfo_encryption_enc_values_supported?: list<non-empty-string>, request_object_signing_alg_values_supported?: list<non-empty-string>, request_object_encryption_alg_values_supported?: list<non-empty-string>, request_object_encryption_enc_values_supported?: list<non-empty-string>, token_endpoint_auth_methods_supported?: list<OpenIdAuthMethod>, token_endpoint_auth_signing_alg_values_supported?: list<non-empty-string>, display_values_supported?: list<OpenIdDisplayType>, claim_types_supported?: list<OpenIdClaimType>, claims_supported?: list<non-empty-string>, service_documentation?: non-empty-string, claims_locales_supported?: list<non-empty-string>, ui_locales_supported?: list<non-empty-string>, claims_parameter_supported?: bool, request_parameter_supported?: bool, request_uri_parameter_supported?: bool, require_request_uri_registration?: bool, op_policy_uri?: non-empty-string, op_tos_uri?: non-empty-string, check_session_iframe?: non-empty-string, code_challenge_methods_supported?: list<non-empty-string>, authorization_signing_alg_values_supported?: list<non-empty-string>, authorization_encryption_alg_values_supported?: list<non-empty-string>, authorization_encryption_enc_values_supported?: list<non-empty-string>, introspection_endpoint?: non-empty-string, introspection_endpoint_auth_methods_supported?: list<non-empty-string>, introspection_endpoint_auth_signing_alg_values_supported?: list<non-empty-string>, introspection_signing_alg_values_supported?: list<non-empty-string>, introspection_encryption_alg_values_supported?: list<non-empty-string>, introspection_encryption_enc_values_supported?: list<non-empty-string>, revocation_endpoint?: non-empty-string, revocation_endpoint_auth_methods_supported?: list<non-empty-string>, revocation_endpoint_auth_signing_alg_values_supported?: list<non-empty-string>, end_session_iframe?: non-empty-string, frontchannel_logout_supported?: bool, frontchannel_logout_session_supported?: bool, backchannel_logout_supported?: bool, backchannel_logout_session_supported?: bool, mtls_endpoint_aliases?: array<string, string>, tls_client_certificate_bound_access_tokens?: bool}&array<string, mixed>
* @psalm-type JWTHeaderObject = array{alg?: non-empty-string, enc?: non-empty-string, jku?: non-empty-string, jwk?: non-empty-string, kid?: non-empty-string, x5u?: non-empty-string, x5c?: non-empty-string, x5t?: non-empty-string, "x5t#S256"?: non-empty-string, typ?: non-empty-string, cty?: non-empty-string, crit?: non-empty-string}
* @psalm-type JWTPayloadObject = array{tid?: string}&array<string, mixed>
* @psalm-type JWTPayloadObject = array<string, mixed>
*/
interface PsalmTypes
{

View file

@ -8,19 +8,23 @@ use Facile\JoseVerifier\JWK\JwksProviderInterface;
/**
* @template TVerifier of TokenVerifierInterface
*
* @psalm-import-type ClientMetadataObject from Psalm\PsalmTypes
* @psalm-import-type IssuerMetadataObject from Psalm\PsalmTypes
*
* @psalm-type IssuerMetadataObject = array{issuer: string, jwks_uri: string}&array<string, mixed>
*/
interface TokenVerifierBuilderInterface
{
/**
* @param array<string, mixed> $clientMetadata
*
* @psalm-param ClientMetadataObject $clientMetadata
*/
public function setClientMetadata(array $clientMetadata): void;
/**
* @param array<string, mixed> $issuerMetadata
*
* @psalm-param IssuerMetadataObject $issuerMetadata
*/
public function setIssuerMetadata(array $issuerMetadata): void;

View file

@ -27,6 +27,7 @@ interface TokenVerifierInterface
* @throws InvalidTokenException
*
* @return array The JWT Payload
*
* @psalm-return JWTPayloadObject
*/
public function verify(string $jwt): array;

View file

@ -4,23 +4,22 @@ declare(strict_types=1);
namespace Facile\JoseVerifier;
use Jose\Easy\Validate;
use Throwable;
final class UserInfoVerifier extends AbstractTokenVerifier
{
/**
* @inheritDoc
*
* @psalm-suppress MixedReturnTypeCoercion
*/
public function verify(string $jwt): array
{
$jwt = $this->decrypt($jwt);
/** @var Validate $validator */
$validator = $this->create($jwt)->mandatory(['sub']);
try {
return $validator->run()->claims->all();
return $validator->run();
} catch (Throwable $e) {
throw $this->processException($e);
}

View file

@ -4,30 +4,70 @@ declare(strict_types=1);
namespace Facile\JoseVerifier\Validate;
use function count;
use Facile\JoseVerifier\Exception\RuntimeException;
use Jose\Component\Checker;
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\JWKSet;
use Jose\Component\Core\Util\JsonConverter;
use Jose\Component\Signature\Algorithm;
use Jose\Component\Signature\JWSTokenSupport;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Jose\Easy\AbstractLoader;
use Jose\Easy\JWT;
use Throwable;
class Validate extends AbstractLoader
/**
* @internal
*/
final class Validate
{
/** @var string */
protected $token;
/** @var JWKSet */
protected $jwkset;
/** @var Checker\HeaderChecker[] */
protected $headerCheckers = [];
/** @var Checker\ClaimChecker[] */
protected $claimCheckers = [];
/** @var \Jose\Component\Core\Algorithm[] */
protected $algorithms = [];
/** @var string[] */
protected $mandatoryClaims = [];
protected function __construct(string $token)
{
$this->token = $token;
$this->jwkset = new JWKSet([]);
$this->claimCheckers = [];
foreach ($this->getAlgorithmMap() as $algorithmClass) {
if (class_exists($algorithmClass)) {
try {
$this->algorithms[] = new $algorithmClass();
} catch (Throwable $throwable) {
//does nothing
}
}
}
}
public static function token(string $token): self
{
return new self($token);
}
public function run(): JWT
/**
* @throws Checker\InvalidClaimException
* @throws Checker\MissingMandatoryClaimException
*
* @return array<string, mixed>
*/
public function run(): array
{
if (0 !== count($this->allowedAlgorithms)) {
$this->headerCheckers[] = new Checker\AlgorithmChecker($this->allowedAlgorithms, true);
}
$jws = (new CompactSerializer())->unserialize($this->token);
$headerChecker = new Checker\HeaderCheckerManager($this->headerCheckers, [new JWSTokenSupport()]);
$headerChecker->check($jws, 0);
@ -37,21 +77,23 @@ class Validate extends AbstractLoader
throw new RuntimeException('Invalid signature');
}
$jwt = new JWT();
$jwt->header->replace($jws->getSignature(0)->getProtectedHeader());
/** @var array<string, mixed> $claims */
$claims = JsonConverter::decode($jws->getPayload() ?? '{}');
$jwt->claims->replace($claims);
$claimChecker = new Checker\ClaimCheckerManager($this->claimCheckers);
$claimChecker->check($jwt->claims->all(), $this->mandatoryClaims);
$claimChecker->check($claims, $this->mandatoryClaims);
return $jwt;
return $claims;
}
/**
* @return string[]
*
* @psalm-return list<class-string<Algorithm\SignatureAlgorithm>>
*
* @psalm-suppress UndefinedClass
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress InvalidReturnType
*/
protected function getAlgorithmMap(): array
{
@ -72,4 +114,41 @@ class Validate extends AbstractLoader
Algorithm\EdDSA::class,
];
}
/**
* @param string[] $mandatoryClaims
*/
public function mandatory(array $mandatoryClaims): self
{
$clone = clone $this;
$clone->mandatoryClaims = $mandatoryClaims;
return $clone;
}
public function claim(Checker\ClaimChecker $checker): self
{
$clone = clone $this;
$clone->claimCheckers[] = $checker;
return $clone;
}
public function header(Checker\HeaderChecker $checker): self
{
$clone = clone $this;
$clone->headerCheckers[] = $checker;
return $clone;
}
public function keyset(JWKSet $jwkset): self
{
$clone = clone $this;
$clone->jwkset = $jwkset;
return $clone;
}
}

View file

@ -10,6 +10,9 @@ use Jose\Component\Core\JWK;
use function round;
use function substr;
/**
* @internal
*/
function derived_key(string $secret, int $length): JWK
{
$hash = substr(hash('sha256', $secret, true), 0, (int) round($length / 8));

View file

@ -8,6 +8,9 @@ use Base64Url\Base64Url;
use Jose\Component\Core\JWK;
use function preg_match;
/**
* @internal
*/
function jose_secret_key(string $secret, ?string $alg = null): JWK
{
if (null !== $alg && (bool) preg_match('/^A(\d{3})(?:GCM)?KW$/', $alg, $matches)) {

View file

@ -1,32 +0,0 @@
<?php
declare(strict_types=1);
namespace Jose\Easy;
use Jose\Component\Core\Algorithm;
use Throwable;
final class AlgorithmProvider
{
/**
* @param list<class-string<Algorithm>> $algorithmClasses
*/
public function __construct(array $algorithmClasses)
{
}
/**
* @return list<class-string<Algorithm>>
*/
public function getAlgorithmClasses(): array
{
}
/**
* @return list<Algorithm>
*/
public function getAvailableAlgorithms(): array
{
}
}

View file

@ -1,61 +0,0 @@
#### v2.5.0 (2022-12)
* Support PHP 8.2 [#99](https://github.com/fgrosse/PHPASN1/pull/99)
* PHP 8 compatibility fix for DateTime::getLastErrors [#98](https://github.com/fgrosse/PHPASN1/pull/98)
* Support more OIDs [#95](https://github.com/fgrosse/PHPASN1/pull/95)
* FINAL RELEASE. Library is now no longer actively maintained and marked as archived on GitHub
#### v2.4.0 (2021-12)
* Drop support for PHP 7.0 [#89](https://github.com/fgrosse/PHPASN1/pull/89)
#### v2.3.1 (2021-12)
* Add `#[\ReturnTypeWillChange]` attributes for PHP 8.1 compatibility [#87](https://github.com/fgrosse/PHPASN1/pull/87)
#### v2.3.0 (2021-04)
* Allow creating an unsigned CSR and adding the signature later [#82](https://github.com/fgrosse/PHPASN1/pull/82)
#### v2.2.0 (2020-08)
* support polyfills for bcmath and gmp, and add a composer.json
suggestion for the `phpseclib/bcmath_polyfill` for servers unable
to install PHP the gmp or bcmath extensions.
#### v.2.1.1 & &v.2.0.2 (2018-12)
* add stricter validation around some structures, highlighed
by wycheproof test suite
#### v.2.1.0 (2018-03)
* add support for `bcmath` extension (making `gmp` optional) [#68](https://github.com/fgrosse/PHPASN1/pull/68)
#### v.2.0.1 & v.1.5.3 (2017-12)
* add .gitattributes file to prevent examples and tests to be installed via composer when --prefer-dist was set
#### v.2.0.0 (2017-08)
* rename `FG\ASN1\Object` to `FG\ASN1\ASNObject` because `Object` is a special class name in the next major PHP release
- when you upgrade you have to adapt all corresponding `use` and `extends` statements as well as type hints and all
usages of `Object::fromBinary(…)`.
* generally drop PHP 5.6 support
#### v.1.5.2 (2016-10-29)
* allow empty octet strings
#### v.1.5.1 (2015-10-02)
* add keywords to composer.json (this is a version on its own so the keywords are found on a stable version at packagist.org)
#### v.1.5.0 (2015-10-30)
* fix a bug that would prevent you from decoding context specific tags on multiple objects [#57](https://github.com/fgrosse/PHPASN1/issues/57)
- `ExplicitlyTaggedObject::__construct` does now accept multiple objects to be tagged with a single tag
- `ExplicitlyTaggedObject::getContent` will now always return an array (even if only one object is tagged)
#### v.1.4.2 (2015-09-29)
* fix a bug that would prevent you from decoding empty tagged objects [#57](https://github.com/fgrosse/PHPASN1/issues/57)
#### v.1.4.1
* improve exception messages and general error handling [#55](https ://github.com/fgrosse/PHPASN1/pull/55)
#### v.1.4.0
* **require PHP 5.6**
* support big integers (closes #1 and #37)
* enforce one code style via [styleci.io][9]
* track code coverage via [coveralls.io][10]
* replace obsolete `FG\ASN1\Exception\GeneralException` with `\Exception`
* `Construct` (`Sequence`, `Set`) does now implement `ArrayAccess`, `Countable` and `Iterator` so its easier to use
* add [`TemplateParser`][11]

View file

@ -1,169 +0,0 @@
PHPASN1
=======
[![Build Status](https://github.com/fgrosse/PHPASN1/actions/workflows/phpunit.yml/badge.svg)](https://github.com/fgrosse/PHPASN1/actions/workflows/phpunit.yml)
[![PHP 7 ready](http://php7ready.timesplinter.ch/fgrosse/PHPASN1/badge.svg)](https://travis-ci.org/fgrosse/PHPASN1)
[![Coverage Status](https://coveralls.io/repos/fgrosse/PHPASN1/badge.svg?branch=master&service=github)](https://coveralls.io/github/fgrosse/PHPASN1?branch=master)
[![Latest Stable Version](https://poser.pugx.org/fgrosse/phpasn1/v/stable.png)](https://packagist.org/packages/fgrosse/phpasn1)
[![Total Downloads](https://poser.pugx.org/fgrosse/phpasn1/downloads.png)](https://packagist.org/packages/fgrosse/phpasn1)
[![Latest Unstable Version](https://poser.pugx.org/fgrosse/phpasn1/v/unstable.png)](https://packagist.org/packages/fgrosse/phpasn1)
[![License](https://poser.pugx.org/fgrosse/phpasn1/license.png)](https://packagist.org/packages/fgrosse/phpasn1)
---
<h2><span style="color:red">Notice: This library is no longer actively maintained!</span></h2>
If you are currently using PHPASN1, this might not be an immediate problem for you, since this library was always rather stable.
However, you are advised to migrate to alternative packages to ensure that your applications remain functional also with newer PHP versions.
---
A PHP Framework that allows you to encode and decode arbitrary [ASN.1][3] structures
using the [ITU-T X.690 Encoding Rules][4].
This encoding is very frequently used in [X.509 PKI environments][5] or the communication between heterogeneous computer systems.
The API allows you to encode ASN.1 structures to create binary data such as certificate
signing requests (CSR), X.509 certificates or certificate revocation lists (CRL).
PHPASN1 can also read [BER encoded][6] binary data into separate PHP objects that can be manipulated by the user and reencoded afterwards.
The **changelog** can now be found at [CHANGELOG.md](CHANGELOG.md).
## Dependencies
PHPASN1 requires at least `PHP 7.0` and either the `gmp` or `bcmath` extension.
Support for older PHP versions (i.e. PHP 5.6) was dropped starting with `v2.0`.
If you must use an outdated PHP version consider using [PHPASN v1.5][13].
For the loading of object identifier names directly from the web [curl][7] is used.
## Installation
The preferred way to install this library is to rely on [Composer][2]:
```bash
$ composer require fgrosse/phpasn1
```
## Usage
### Encoding ASN.1 Structures
PHPASN1 offers you a class for each of the implemented ASN.1 universal types.
The constructors should be pretty self explanatory so you should have no big trouble getting started.
All data will be encoded using [DER encoding][8]
```php
use FG\ASN1\OID;
use FG\ASN1\Universal\Integer;
use FG\ASN1\Universal\Boolean;
use FG\ASN1\Universal\Enumerated;
use FG\ASN1\Universal\IA5String;
use FG\ASN1\Universal\ObjectIdentifier;
use FG\ASN1\Universal\PrintableString;
use FG\ASN1\Universal\Sequence;
use FG\ASN1\Universal\Set;
use FG\ASN1\Universal\NullObject;
$integer = new Integer(123456);
$boolean = new Boolean(true);
$enum = new Enumerated(1);
$ia5String = new IA5String('Hello world');
$asnNull = new NullObject();
$objectIdentifier1 = new ObjectIdentifier('1.2.250.1.16.9');
$objectIdentifier2 = new ObjectIdentifier(OID::RSA_ENCRYPTION);
$printableString = new PrintableString('Foo bar');
$sequence = new Sequence($integer, $boolean, $enum, $ia5String);
$set = new Set($sequence, $asnNull, $objectIdentifier1, $objectIdentifier2, $printableString);
$myBinary = $sequence->getBinary();
$myBinary .= $set->getBinary();
echo base64_encode($myBinary);
```
### Decoding binary data
Decoding BER encoded binary data is just as easy as encoding it:
```php
use FG\ASN1\ASNObject;
$base64String = ...
$binaryData = base64_decode($base64String);
$asnObject = ASNObject::fromBinary($binaryData);
// do stuff
```
If you already know exactly how your expected data should look like you can use the `FG\ASN1\TemplateParser`:
```php
use FG\ASN1\TemplateParser;
// first define your template
$template = [
Identifier::SEQUENCE => [
Identifier::SET => [
Identifier::OBJECT_IDENTIFIER,
Identifier::SEQUENCE => [
Identifier::INTEGER,
Identifier::BITSTRING,
]
]
]
];
// if your binary data is not matching the template you provided this will throw an `\Exception`:
$parser = new TemplateParser();
$object = $parser->parseBinary($data, $template);
// there is also a convenience function if you parse binary data from base64:
$object = $parser->parseBase64($data, $template);
```
You can use this function to make sure your data has exactly the format you are expecting.
### Navigating decoded data
All constructed classes (i.e. `Sequence` and `Set`) can be navigated by array access or using an iterator.
You can find examples
[here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L148-148),
[here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L121) and
[here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/TemplateParserTest.php#L45).
### Give me more examples!
To see some example usage of the API classes or some generated output check out the [examples](https://github.com/fgrosse/PHPASN1/tree/master/examples).
### How do I contribute?
This project is no longer maintained and thus does not accept any new contributions.
### Thanks
To [all contributors][1] so far!
## License
This library is distributed under the [MIT License](LICENSE).
[1]: https://github.com/fgrosse/PHPASN1/graphs/contributors
[2]: https://getcomposer.org/
[3]: http://www.itu.int/ITU-T/asn1/
[4]: http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=x.690
[5]: http://en.wikipedia.org/wiki/X.509
[6]: http://en.wikipedia.org/wiki/X.690#BER_encoding
[7]: http://php.net/manual/en/book.curl.php
[8]: http://en.wikipedia.org/wiki/X.690#DER_encoding
[9]: https://styleci.io
[10]: https://coveralls.io/github/fgrosse/PHPASN1
[11]: https://github.com/fgrosse/PHPASN1/blob/master/tests/ASN1/TemplateParserTest.php#L16
[12]: https://groups.google.com/d/forum/phpasn1
[13]: https://packagist.org/packages/fgrosse/phpasn1#1.5.2

View file

@ -1,49 +0,0 @@
{
"name": "fgrosse/phpasn1",
"description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.",
"type": "library",
"homepage": "https://github.com/FGrosse/PHPASN1",
"license": "MIT",
"authors": [
{
"name": "Friedrich Große",
"email": "friedrich.grosse@gmail.com",
"homepage": "https://github.com/FGrosse",
"role": "Author"
},
{
"name": "All contributors",
"homepage": "https://github.com/FGrosse/PHPASN1/contributors"
}
],
"keywords": [ "x690", "x.690", "x.509", "x509", "asn1", "asn.1", "ber", "der", "binary", "encoding", "decoding" ],
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"php-coveralls/php-coveralls": "~2.0"
},
"suggest": {
"ext-gmp": "GMP is the preferred extension for big integer calculations",
"ext-bcmath": "BCmath is the fallback extension for big integer calculations",
"phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available",
"ext-curl": "For loading OID information from the web if they have not bee defined statically"
},
"autoload": {
"psr-4": {
"FG\\": "lib/"
}
},
"autoload-dev": {
"psr-4": {
"FG\\Test\\": "tests/"
}
},
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
}
}

View file

@ -1,355 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1;
use FG\ASN1\Exception\ParserException;
use FG\ASN1\Universal\BitString;
use FG\ASN1\Universal\Boolean;
use FG\ASN1\Universal\Enumerated;
use FG\ASN1\Universal\GeneralizedTime;
use FG\ASN1\Universal\Integer;
use FG\ASN1\Universal\NullObject;
use FG\ASN1\Universal\ObjectIdentifier;
use FG\ASN1\Universal\RelativeObjectIdentifier;
use FG\ASN1\Universal\OctetString;
use FG\ASN1\Universal\Sequence;
use FG\ASN1\Universal\Set;
use FG\ASN1\Universal\UTCTime;
use FG\ASN1\Universal\IA5String;
use FG\ASN1\Universal\PrintableString;
use FG\ASN1\Universal\NumericString;
use FG\ASN1\Universal\UTF8String;
use FG\ASN1\Universal\UniversalString;
use FG\ASN1\Universal\CharacterString;
use FG\ASN1\Universal\GeneralString;
use FG\ASN1\Universal\VisibleString;
use FG\ASN1\Universal\GraphicString;
use FG\ASN1\Universal\BMPString;
use FG\ASN1\Universal\T61String;
use FG\ASN1\Universal\ObjectDescriptor;
use FG\Utility\BigInteger;
use LogicException;
/**
* Class ASNObject is the base class for all concrete ASN.1 objects.
*/
abstract class ASNObject implements Parsable
{
private $contentLength;
private $nrOfLengthOctets;
/**
* Must return the number of octets of the content part.
*
* @return int
*/
abstract protected function calculateContentLength();
/**
* Encode the object using DER encoding.
*
* @see http://en.wikipedia.org/wiki/X.690#DER_encoding
*
* @return string the binary representation of an objects value
*/
abstract protected function getEncodedValue();
/**
* Return the content of this object in a non encoded form.
* This can be used to print the value in human readable form.
*
* @return mixed
*/
abstract public function getContent();
/**
* Return the object type octet.
* This should use the class constants of Identifier.
*
* @see Identifier
*
* @return int
*/
abstract public function getType();
/**
* Returns all identifier octets. If an inheriting class models a tag with
* the long form identifier format, it MUST reimplement this method to
* return all octets of the identifier.
*
* @throws LogicException If the identifier format is long form
*
* @return string Identifier as a set of octets
*/
public function getIdentifier()
{
$firstOctet = $this->getType();
if (Identifier::isLongForm($firstOctet)) {
throw new LogicException(sprintf('Identifier of %s uses the long form and must therefor override "ASNObject::getIdentifier()".', get_class($this)));
}
return chr($firstOctet);
}
/**
* Encode this object using DER encoding.
*
* @return string the full binary representation of the complete object
*/
public function getBinary()
{
$result = $this->getIdentifier();
$result .= $this->createLengthPart();
$result .= $this->getEncodedValue();
return $result;
}
private function createLengthPart()
{
$contentLength = $this->getContentLength();
$nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength);
if ($nrOfLengthOctets == 1) {
return chr($contentLength);
} else {
// the first length octet determines the number subsequent length octets
$lengthOctets = chr(0x80 | ($nrOfLengthOctets - 1));
for ($shiftLength = 8 * ($nrOfLengthOctets - 2); $shiftLength >= 0; $shiftLength -= 8) {
$lengthOctets .= chr($contentLength >> $shiftLength);
}
return $lengthOctets;
}
}
protected function getNumberOfLengthOctets($contentLength = null)
{
if (!isset($this->nrOfLengthOctets)) {
if ($contentLength == null) {
$contentLength = $this->getContentLength();
}
$this->nrOfLengthOctets = 1;
if ($contentLength > 127) {
do { // long form
$this->nrOfLengthOctets++;
$contentLength = $contentLength >> 8;
} while ($contentLength > 0);
}
}
return $this->nrOfLengthOctets;
}
protected function getContentLength()
{
if (!isset($this->contentLength)) {
$this->contentLength = $this->calculateContentLength();
}
return $this->contentLength;
}
protected function setContentLength($newContentLength)
{
$this->contentLength = $newContentLength;
$this->getNumberOfLengthOctets($newContentLength);
}
/**
* Returns the length of the whole object (including the identifier and length octets).
*/
public function getObjectLength()
{
$nrOfIdentifierOctets = strlen($this->getIdentifier());
$contentLength = $this->getContentLength();
$nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength);
return $nrOfIdentifierOctets + $nrOfLengthOctets + $contentLength;
}
public function __toString()
{
return $this->getContent();
}
/**
* Returns the name of the ASN.1 Type of this object.
*
* @see Identifier::getName()
*/
public function getTypeName()
{
return Identifier::getName($this->getType());
}
/**
* @param string $binaryData
* @param int $offsetIndex
*
* @throws ParserException
*
* @return \FG\ASN1\ASNObject
*/
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
{
if (strlen($binaryData) <= $offsetIndex) {
throw new ParserException('Can not parse binary from data: Offset index larger than input size', $offsetIndex);
}
$identifierOctet = ord($binaryData[$offsetIndex]);
if (Identifier::isContextSpecificClass($identifierOctet) && Identifier::isConstructed($identifierOctet)) {
return ExplicitlyTaggedObject::fromBinary($binaryData, $offsetIndex);
}
switch ($identifierOctet) {
case Identifier::BITSTRING:
return BitString::fromBinary($binaryData, $offsetIndex);
case Identifier::BOOLEAN:
return Boolean::fromBinary($binaryData, $offsetIndex);
case Identifier::ENUMERATED:
return Enumerated::fromBinary($binaryData, $offsetIndex);
case Identifier::INTEGER:
return Integer::fromBinary($binaryData, $offsetIndex);
case Identifier::NULL:
return NullObject::fromBinary($binaryData, $offsetIndex);
case Identifier::OBJECT_IDENTIFIER:
return ObjectIdentifier::fromBinary($binaryData, $offsetIndex);
case Identifier::RELATIVE_OID:
return RelativeObjectIdentifier::fromBinary($binaryData, $offsetIndex);
case Identifier::OCTETSTRING:
return OctetString::fromBinary($binaryData, $offsetIndex);
case Identifier::SEQUENCE:
return Sequence::fromBinary($binaryData, $offsetIndex);
case Identifier::SET:
return Set::fromBinary($binaryData, $offsetIndex);
case Identifier::UTC_TIME:
return UTCTime::fromBinary($binaryData, $offsetIndex);
case Identifier::GENERALIZED_TIME:
return GeneralizedTime::fromBinary($binaryData, $offsetIndex);
case Identifier::IA5_STRING:
return IA5String::fromBinary($binaryData, $offsetIndex);
case Identifier::PRINTABLE_STRING:
return PrintableString::fromBinary($binaryData, $offsetIndex);
case Identifier::NUMERIC_STRING:
return NumericString::fromBinary($binaryData, $offsetIndex);
case Identifier::UTF8_STRING:
return UTF8String::fromBinary($binaryData, $offsetIndex);
case Identifier::UNIVERSAL_STRING:
return UniversalString::fromBinary($binaryData, $offsetIndex);
case Identifier::CHARACTER_STRING:
return CharacterString::fromBinary($binaryData, $offsetIndex);
case Identifier::GENERAL_STRING:
return GeneralString::fromBinary($binaryData, $offsetIndex);
case Identifier::VISIBLE_STRING:
return VisibleString::fromBinary($binaryData, $offsetIndex);
case Identifier::GRAPHIC_STRING:
return GraphicString::fromBinary($binaryData, $offsetIndex);
case Identifier::BMP_STRING:
return BMPString::fromBinary($binaryData, $offsetIndex);
case Identifier::T61_STRING:
return T61String::fromBinary($binaryData, $offsetIndex);
case Identifier::OBJECT_DESCRIPTOR:
return ObjectDescriptor::fromBinary($binaryData, $offsetIndex);
default:
// At this point the identifier may be >1 byte.
if (Identifier::isConstructed($identifierOctet)) {
return new UnknownConstructedObject($binaryData, $offsetIndex);
} else {
$identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex);
$lengthOfUnknownObject = self::parseContentLength($binaryData, $offsetIndex);
$offsetIndex += $lengthOfUnknownObject;
return new UnknownObject($identifier, $lengthOfUnknownObject);
}
}
}
protected static function parseIdentifier($identifierOctet, $expectedIdentifier, $offsetForExceptionHandling)
{
if (is_string($identifierOctet) || is_numeric($identifierOctet) == false) {
$identifierOctet = ord($identifierOctet);
}
if ($identifierOctet != $expectedIdentifier) {
$message = 'Can not create an '.Identifier::getName($expectedIdentifier).' from an '.Identifier::getName($identifierOctet);
throw new ParserException($message, $offsetForExceptionHandling);
}
}
protected static function parseBinaryIdentifier($binaryData, &$offsetIndex)
{
if (strlen($binaryData) <= $offsetIndex) {
throw new ParserException('Can not parse identifier from data: Offset index larger than input size', $offsetIndex);
}
$identifier = $binaryData[$offsetIndex++];
if (Identifier::isLongForm(ord($identifier)) == false) {
return $identifier;
}
while (true) {
if (strlen($binaryData) <= $offsetIndex) {
throw new ParserException('Can not parse identifier (long form) from data: Offset index larger than input size', $offsetIndex);
}
$nextOctet = $binaryData[$offsetIndex++];
$identifier .= $nextOctet;
if ((ord($nextOctet) & 0x80) === 0) {
// the most significant bit is 0 to we have reached the end of the identifier
break;
}
}
return $identifier;
}
protected static function parseContentLength(&$binaryData, &$offsetIndex, $minimumLength = 0)
{
if (strlen($binaryData) <= $offsetIndex) {
throw new ParserException('Can not parse content length from data: Offset index larger than input size', $offsetIndex);
}
$contentLength = ord($binaryData[$offsetIndex++]);
if (($contentLength & 0x80) != 0) {
// bit 8 is set -> this is the long form
$nrOfLengthOctets = $contentLength & 0x7F;
$contentLength = BigInteger::create(0x00);
for ($i = 0; $i < $nrOfLengthOctets; $i++) {
if (strlen($binaryData) <= $offsetIndex) {
throw new ParserException('Can not parse content length (long form) from data: Offset index larger than input size', $offsetIndex);
}
$contentLength = $contentLength->shiftLeft(8)->add(ord($binaryData[$offsetIndex++]));
}
if ($contentLength->compare(PHP_INT_MAX) > 0) {
throw new ParserException("Can not parse content length from data: length > maximum integer", $offsetIndex);
}
$contentLength = $contentLength->toInteger();
}
if ($contentLength < $minimumLength) {
throw new ParserException('A '.get_called_class()." should have a content length of at least {$minimumLength}. Extracted length was {$contentLength}", $offsetIndex);
}
$lenDataRemaining = strlen($binaryData) - $offsetIndex;
if ($lenDataRemaining < $contentLength) {
throw new ParserException("Content length {$contentLength} exceeds remaining data length {$lenDataRemaining}", $offsetIndex);
}
return $contentLength;
}
}

View file

@ -1,136 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1;
use Exception;
abstract class AbstractString extends ASNObject implements Parsable
{
/** @var string */
protected $value;
private $checkStringForIllegalChars = true;
private $allowedCharacters = [];
/**
* The abstract base class for ASN.1 classes which represent some string of character.
*
* @param string $string
*/
public function __construct($string)
{
$this->value = $string;
}
public function getContent()
{
return $this->value;
}
protected function allowCharacter($character)
{
$this->allowedCharacters[] = $character;
}
protected function allowCharacters(...$characters)
{
foreach ($characters as $character) {
$this->allowedCharacters[] = $character;
}
}
protected function allowNumbers()
{
foreach (range('0', '9') as $char) {
$this->allowedCharacters[] = (string) $char;
}
}
protected function allowAllLetters()
{
$this->allowSmallLetters();
$this->allowCapitalLetters();
}
protected function allowSmallLetters()
{
foreach (range('a', 'z') as $char) {
$this->allowedCharacters[] = $char;
}
}
protected function allowCapitalLetters()
{
foreach (range('A', 'Z') as $char) {
$this->allowedCharacters[] = $char;
}
}
protected function allowSpaces()
{
$this->allowedCharacters[] = ' ';
}
protected function allowAll()
{
$this->checkStringForIllegalChars = false;
}
protected function calculateContentLength()
{
return strlen($this->value);
}
protected function getEncodedValue()
{
if ($this->checkStringForIllegalChars) {
$this->checkString();
}
return $this->value;
}
protected function checkString()
{
$stringLength = $this->getContentLength();
for ($i = 0; $i < $stringLength; $i++) {
if (in_array($this->value[$i], $this->allowedCharacters) == false) {
$typeName = Identifier::getName($this->getType());
throw new Exception("Could not create a {$typeName} from the character sequence '{$this->value}'.");
}
}
}
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
{
$parsedObject = new static('');
self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++);
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
$string = substr($binaryData, $offsetIndex, $contentLength);
$offsetIndex += $contentLength;
$parsedObject->value = $string;
$parsedObject->setContentLength($contentLength);
return $parsedObject;
}
public static function isValid($string)
{
$testObject = new static($string);
try {
$testObject->checkString();
return true;
} catch (Exception $exception) {
return false;
}
}
}

View file

@ -1,78 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1;
use DateInterval;
use DateTime;
use DateTimeZone;
use Exception;
abstract class AbstractTime extends ASNObject
{
/** @var DateTime */
protected $value;
public function __construct($dateTime = null, $dateTimeZone = 'UTC')
{
if ($dateTime == null || is_string($dateTime)) {
$timeZone = new DateTimeZone($dateTimeZone);
$dateTimeObject = new DateTime($dateTime, $timeZone);
if ($dateTimeObject == false) {
$errorMessage = $this->getLastDateTimeErrors();
$className = Identifier::getName($this->getType());
throw new Exception(sprintf("Could not create %s from date time string '%s': %s", $className, $dateTime, $errorMessage));
}
$dateTime = $dateTimeObject;
} elseif (!$dateTime instanceof DateTime) {
throw new Exception('Invalid first argument for some instance of AbstractTime constructor');
}
$this->value = $dateTime;
}
public function getContent()
{
return $this->value;
}
protected function getLastDateTimeErrors()
{
$messages = '';
$lastErrors = DateTime::getLastErrors() ?: ['errors' => []];
foreach ($lastErrors['errors'] as $errorMessage) {
$messages .= "{$errorMessage}, ";
}
return substr($messages, 0, -2);
}
public function __toString()
{
return $this->value->format("Y-m-d\tH:i:s");
}
protected static function extractTimeZoneData(&$binaryData, &$offsetIndex, DateTime $dateTime)
{
$sign = $binaryData[$offsetIndex++];
$timeOffsetHours = intval(substr($binaryData, $offsetIndex, 2));
$timeOffsetMinutes = intval(substr($binaryData, $offsetIndex + 2, 2));
$offsetIndex += 4;
$interval = new DateInterval("PT{$timeOffsetHours}H{$timeOffsetMinutes}M");
if ($sign == '+') {
$dateTime->sub($interval);
} else {
$dateTime->add($interval);
}
return $dateTime;
}
}

View file

@ -1,63 +0,0 @@
<?php
namespace FG\ASN1;
use FG\Utility\BigInteger;
use InvalidArgumentException;
/**
* A base-128 decoder.
*/
class Base128
{
/**
* @param int $value
*
* @return string
*/
public static function encode($value)
{
$value = BigInteger::create($value);
$octets = chr($value->modulus(0x80)->toInteger());
$value = $value->shiftRight(7);
while ($value->compare(0) > 0) {
$octets .= chr(0x80 | $value->modulus(0x80)->toInteger());
$value = $value->shiftRight(7);
}
return strrev($octets);
}
/**
* @param string $octets
*
* @throws InvalidArgumentException if the given octets represent a malformed base-128 value or the decoded value would exceed the the maximum integer length
*
* @return int
*/
public static function decode($octets)
{
$bitsPerOctet = 7;
$value = BigInteger::create(0);
$i = 0;
while (true) {
if (!isset($octets[$i])) {
throw new InvalidArgumentException(sprintf('Malformed base-128 encoded value (0x%s).', strtoupper(bin2hex($octets)) ?: '0'));
}
$octet = ord($octets[$i++]);
$l1 = $value->shiftLeft($bitsPerOctet);
$r1 = $octet & 0x7f;
$value = $l1->add($r1);
if (0 === ($octet & 0x80)) {
break;
}
}
return (string)$value;
}
}

View file

@ -1,35 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1\Composite;
use FG\ASN1\ASNObject;
use FG\ASN1\Universal\Sequence;
use FG\ASN1\Universal\ObjectIdentifier;
class AttributeTypeAndValue extends Sequence
{
/**
* @param ObjectIdentifier|string $objIdentifier
* @param \FG\ASN1\ASNObject $value
*/
public function __construct($objIdentifier, ASNObject $value)
{
if ($objIdentifier instanceof ObjectIdentifier == false) {
$objIdentifier = new ObjectIdentifier($objIdentifier);
}
parent::__construct($objIdentifier, $value);
}
public function __toString()
{
return $this->children[0].': '.$this->children[1];
}
}

View file

@ -1,37 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1\Composite;
use FG\ASN1\Universal\PrintableString;
use FG\ASN1\Universal\IA5String;
use FG\ASN1\Universal\UTF8String;
class RDNString extends RelativeDistinguishedName
{
/**
* @param string|\FG\ASN1\Universal\ObjectIdentifier $objectIdentifierString
* @param string|\FG\ASN1\ASNObject $value
*/
public function __construct($objectIdentifierString, $value)
{
if (PrintableString::isValid($value)) {
$value = new PrintableString($value);
} else {
if (IA5String::isValid($value)) {
$value = new IA5String($value);
} else {
$value = new UTF8String($value);
}
}
parent::__construct($objectIdentifierString, $value);
}
}

View file

@ -1,50 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1\Composite;
use FG\ASN1\Exception\NotImplementedException;
use FG\ASN1\ASNObject;
use FG\ASN1\Universal\Set;
class RelativeDistinguishedName extends Set
{
/**
* @param string|\FG\ASN1\Universal\ObjectIdentifier $objIdentifierString
* @param \FG\ASN1\ASNObject $value
*/
public function __construct($objIdentifierString, ASNObject $value)
{
// TODO: This does only support one element in the RelativeDistinguishedName Set but it it is defined as follows:
// RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
parent::__construct(new AttributeTypeAndValue($objIdentifierString, $value));
}
public function getContent()
{
/** @var \FG\ASN1\ASNObject $firstObject */
$firstObject = $this->children[0];
return $firstObject->__toString();
}
/**
* At the current version this code can not work since the implementation of Construct requires
* the class to support a constructor without arguments.
*
* @deprecated this function is not yet implemented! Feel free to submit a pull request on github
* @param string $binaryData
* @param int $offsetIndex
* @throws NotImplementedException
*/
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
{
throw new NotImplementedException();
}
}

View file

@ -1,202 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1;
use ArrayAccess;
use ArrayIterator;
use Countable;
use FG\ASN1\Exception\ParserException;
use Iterator;
abstract class Construct extends ASNObject implements Countable, ArrayAccess, Iterator, Parsable
{
/** @var \FG\ASN1\ASNObject[] */
protected $children;
private $iteratorPosition;
/**
* @param \FG\ASN1\ASNObject[] $children the variadic type hint is commented due to https://github.com/facebook/hhvm/issues/4858
*/
public function __construct(/* HH_FIXME[4858]: variadic + strict */ ...$children)
{
$this->children = $children;
$this->iteratorPosition = 0;
}
public function getContent()
{
return $this->children;
}
#[\ReturnTypeWillChange]
public function rewind()
{
$this->iteratorPosition = 0;
}
#[\ReturnTypeWillChange]
public function current()
{
return $this->children[$this->iteratorPosition];
}
#[\ReturnTypeWillChange]
public function key()
{
return $this->iteratorPosition;
}
#[\ReturnTypeWillChange]
public function next()
{
$this->iteratorPosition++;
}
#[\ReturnTypeWillChange]
public function valid()
{
return isset($this->children[$this->iteratorPosition]);
}
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return array_key_exists($offset, $this->children);
}
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->children[$offset];
}
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if ($offset === null) {
$offset = count($this->children);
}
$this->children[$offset] = $value;
}
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->children[$offset]);
}
protected function calculateContentLength()
{
$length = 0;
foreach ($this->children as $component) {
$length += $component->getObjectLength();
}
return $length;
}
protected function getEncodedValue()
{
$result = '';
foreach ($this->children as $component) {
$result .= $component->getBinary();
}
return $result;
}
public function addChild(ASNObject $child)
{
$this->children[] = $child;
}
public function addChildren(array $children)
{
foreach ($children as $child) {
$this->addChild($child);
}
}
public function __toString()
{
$nrOfChildren = $this->getNumberOfChildren();
$childString = $nrOfChildren == 1 ? 'child' : 'children';
return "[{$nrOfChildren} {$childString}]";
}
public function getNumberOfChildren()
{
return count($this->children);
}
/**
* @return \FG\ASN1\ASNObject[]
*/
public function getChildren()
{
return $this->children;
}
/**
* @return \FG\ASN1\ASNObject
*/
public function getFirstChild()
{
return $this->children[0];
}
/**
* @param string $binaryData
* @param int $offsetIndex
*
* @throws Exception\ParserException
*
* @return Construct|static
*/
#[\ReturnTypeWillChange]
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
{
$parsedObject = new static();
self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++);
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
$startIndex = $offsetIndex;
$children = [];
$octetsToRead = $contentLength;
while ($octetsToRead > 0) {
$newChild = ASNObject::fromBinary($binaryData, $offsetIndex);
$octetsToRead -= $newChild->getObjectLength();
$children[] = $newChild;
}
if ($octetsToRead !== 0) {
throw new ParserException("Sequence length incorrect", $startIndex);
}
$parsedObject->addChildren($children);
$parsedObject->setContentLength($contentLength);
return $parsedObject;
}
#[\ReturnTypeWillChange]
public function count($mode = COUNT_NORMAL)
{
return count($this->children, $mode);
}
public function getIterator()
{
return new ArrayIterator($this->children);
}
}

View file

@ -1,15 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1\Exception;
class NotImplementedException extends \Exception
{
}

View file

@ -1,29 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1\Exception;
class ParserException extends \Exception
{
private $errorMessage;
private $offset;
public function __construct($errorMessage, $offset)
{
$this->errorMessage = $errorMessage;
$this->offset = $offset;
parent::__construct("ASN.1 Parser Exception at offset {$this->offset}: {$this->errorMessage}");
}
public function getOffset()
{
return $this->offset;
}
}

View file

@ -1,131 +0,0 @@
<?php
/*
* This file is part of the PHPASN1 library.
*
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FG\ASN1;
use FG\ASN1\Exception\ParserException;
/**
* Class ExplicitlyTaggedObject decorate an inner object with an additional tag that gives information about
* its context specific meaning.
*
* Explanation taken from A Layman's Guide to a Subset of ASN.1, BER, and DER:
* >>> An RSA Laboratories Technical Note
* >>> Burton S. Kaliski Jr.
* >>> Revised November 1, 1993
*
* [...]
* Explicitly tagged types are derived from other types by adding an outer tag to the underlying type.
* In effect, explicitly tagged types are structured types consisting of one component, the underlying type.
* Explicit tagging is denoted by the ASN.1 keywords [class number] EXPLICIT (see Section 5.2).
* [...]
*
* @see http://luca.ntop.org/Teaching/Appunti/asn1.html
*/
class ExplicitlyTaggedObject extends ASNObject
{
/** @var \FG\ASN1\ASNObject[] */
private $decoratedObjects;
private $tag;
/**
* @param int $tag
* @param \FG\ASN1\ASNObject $objects,...
*/
public function __construct($tag, /* HH_FIXME[4858]: variadic + strict */ ...$objects)
{
$this->tag = $tag;
$this->decoratedObjects = $objects;
}
protected function calculateContentLength()
{
$length = 0;
foreach ($this->decoratedObjects as $object) {
$length += $object->getObjectLength();
}
return $length;
}
protected function getEncodedValue()
{
$encoded = '';
foreach ($this->decoratedObjects as $object) {
$encoded .= $object->getBinary();
}
return $encoded;
}
public function getContent()
{
return $this->decoratedObjects;
}
public function __toString()
{
switch ($length = count($this->decoratedObjects)) {
case 0:
return "Context specific empty object with tag [{$this->tag}]";
case 1:
$decoratedType = Identifier::getShortName($this->decoratedObjects[0]->getType());
return "Context specific $decoratedType with tag [{$this->tag}]";
default:
return "$length context specific objects with tag [{$this->tag}]";
}
}
public function getType()
{
return ord($this->getIdentifier());
}
public function getIdentifier()
{
$identifier = Identifier::create(Identifier::CLASS_CONTEXT_SPECIFIC, true, $this->tag);
return is_int($identifier) ? chr($identifier) : $identifier;
}
public function getTag()
{
return $this->tag;
}
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
{
$identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex);
$firstIdentifierOctet = ord($identifier);
assert(Identifier::isContextSpecificClass($firstIdentifierOctet), 'identifier octet should indicate context specific class');
assert(Identifier::isConstructed($firstIdentifierOctet), 'identifier octet should indicate constructed object');
$tag = Identifier::getTagNumber($identifier);
$totalContentLength = self::parseContentLength($binaryData, $offsetIndex);
$remainingContentLength = $totalContentLength;
$offsetIndexOfDecoratedObject = $offsetIndex;
$decoratedObjects = [];
while ($remainingContentLength > 0) {
$nextObject = ASNObject::fromBinary($binaryData, $offsetIndex);
$remainingContentLength -= $nextObject->getObjectLength();
$decoratedObjects[] = $nextObject;
}
if ($remainingContentLength != 0) {
throw new ParserException("Context-Specific explicitly tagged object [$tag] starting at offset $offsetIndexOfDecoratedObject specifies a length of $totalContentLength octets but $remainingContentLength remain after parsing the content", $offsetIndexOfDecoratedObject);
}
$parsedObject = new self($tag, ...$decoratedObjects);
$parsedObject->setContentLength($totalContentLength);
return $parsedObject;
}
}

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