diff --git a/brick/math/LICENSE b/brick/math/LICENSE
new file mode 100644
index 000000000..f9b724f00
--- /dev/null
+++ b/brick/math/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-present Benjamin Morel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/brick/math/SECURITY.md b/brick/math/SECURITY.md
new file mode 100644
index 000000000..6bdc74f0d
--- /dev/null
+++ b/brick/math/SECURITY.md
@@ -0,0 +1,16 @@
+# Security Policy
+
+## Supported Versions
+
+Only the latest release stream is supported.
+
+| Version | Supported |
+| ------- | ------------------ |
+| 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.
diff --git a/brick/math/composer.json b/brick/math/composer.json
new file mode 100644
index 000000000..d347b6bde
--- /dev/null
+++ b/brick/math/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "brick/math",
+ "description": "Arbitrary-precision arithmetic library",
+ "type": "library",
+ "keywords": [
+ "Brick",
+ "Math",
+ "Arbitrary-precision",
+ "Arithmetic",
+ "BigInteger",
+ "BigDecimal",
+ "BigRational",
+ "Bignum"
+ ],
+ "license": "MIT",
+ "require": {
+ "php": "^7.1|^8.0",
+ "ext-json": "*"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5.15|^8.5",
+ "php-coveralls/php-coveralls": "^2.2",
+ "vimeo/psalm": "^3.5"
+ },
+ "autoload": {
+ "psr-4": {
+ "Brick\\Math\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Brick\\Math\\Tests\\": "tests/"
+ }
+ }
+}
diff --git a/brick/math/psalm-baseline.xml b/brick/math/psalm-baseline.xml
new file mode 100644
index 000000000..fe05b998c
--- /dev/null
+++ b/brick/math/psalm-baseline.xml
@@ -0,0 +1,40 @@
+
+
+
+
+ string
+ string
+ string
+
+
+ [$q, $r]
+
+
+ array
+
+
+ \bcdiv($a, $b, 0)
+ \bcmod($a, $b)
+ \bcpowmod($base, $exp, $mod, 0)
+
+
+
+
+ $a
+ $a
+ $a
+ $b
+ $blockA
+ $blockA
+
+
+ $i
+ $i
+ $i
+ $j
+
+
+ $e / 2
+
+
+
diff --git a/brick/math/psalm.xml b/brick/math/psalm.xml
new file mode 100644
index 000000000..123263ef4
--- /dev/null
+++ b/brick/math/psalm.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/brick/math/src/BigDecimal.php b/brick/math/src/BigDecimal.php
new file mode 100644
index 000000000..29bdd320b
--- /dev/null
+++ b/brick/math/src/BigDecimal.php
@@ -0,0 +1,855 @@
+value = $value;
+ $this->scale = $scale;
+ }
+
+ /**
+ * 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
+ {
+ return parent::of($value)->toBigDecimal();
+ }
+
+ /**
+ * Creates a BigDecimal from an unscaled value and a scale.
+ *
+ * Example: `(12345, 3)` will result in the BigDecimal `12.345`.
+ *
+ * @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
+ {
+ if ($scale < 0) {
+ throw new \InvalidArgumentException('The scale cannot be negative.');
+ }
+
+ return new BigDecimal((string) BigInteger::of($value), $scale);
+ }
+
+ /**
+ * Returns a BigDecimal representing zero, with a scale of zero.
+ *
+ * @return BigDecimal
+ *
+ * @psalm-pure
+ */
+ public static function zero() : BigDecimal
+ {
+ /** @psalm-suppress ImpureStaticVariable */
+ static $zero;
+
+ if ($zero === null) {
+ $zero = new BigDecimal('0');
+ }
+
+ return $zero;
+ }
+
+ /**
+ * Returns a BigDecimal representing one, with a scale of zero.
+ *
+ * @return BigDecimal
+ *
+ * @psalm-pure
+ */
+ public static function one() : BigDecimal
+ {
+ /** @psalm-suppress ImpureStaticVariable */
+ static $one;
+
+ if ($one === null) {
+ $one = new BigDecimal('1');
+ }
+
+ return $one;
+ }
+
+ /**
+ * Returns a BigDecimal representing ten, with a scale of zero.
+ *
+ * @return BigDecimal
+ *
+ * @psalm-pure
+ */
+ public static function ten() : BigDecimal
+ {
+ /** @psalm-suppress ImpureStaticVariable */
+ static $ten;
+
+ if ($ten === null) {
+ $ten = new BigDecimal('10');
+ }
+
+ return $ten;
+ }
+
+ /**
+ * Returns the sum of this number and the given one.
+ *
+ * The result has a scale of `max($this->scale, $that->scale)`.
+ *
+ * @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
+ {
+ $that = BigDecimal::of($that);
+
+ if ($that->value === '0' && $that->scale <= $this->scale) {
+ return $this;
+ }
+
+ if ($this->value === '0' && $this->scale <= $that->scale) {
+ return $that;
+ }
+
+ [$a, $b] = $this->scaleValues($this, $that);
+
+ $value = Calculator::get()->add($a, $b);
+ $scale = $this->scale > $that->scale ? $this->scale : $that->scale;
+
+ return new BigDecimal($value, $scale);
+ }
+
+ /**
+ * Returns the difference of this number and the given one.
+ *
+ * The result has a scale of `max($this->scale, $that->scale)`.
+ *
+ * @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
+ {
+ $that = BigDecimal::of($that);
+
+ if ($that->value === '0' && $that->scale <= $this->scale) {
+ return $this;
+ }
+
+ [$a, $b] = $this->scaleValues($this, $that);
+
+ $value = Calculator::get()->sub($a, $b);
+ $scale = $this->scale > $that->scale ? $this->scale : $that->scale;
+
+ return new BigDecimal($value, $scale);
+ }
+
+ /**
+ * Returns the product of this number and the given one.
+ *
+ * The result has a scale of `$this->scale + $that->scale`.
+ *
+ * @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
+ {
+ $that = BigDecimal::of($that);
+
+ if ($that->value === '1' && $that->scale === 0) {
+ return $this;
+ }
+
+ if ($this->value === '1' && $this->scale === 0) {
+ return $that;
+ }
+
+ $value = Calculator::get()->mul($this->value, $that->value);
+ $scale = $this->scale + $that->scale;
+
+ return new BigDecimal($value, $scale);
+ }
+
+ /**
+ * Returns the result of the division of this number by the given one, at the given scale.
+ *
+ * @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
+ *
+ * @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
+ {
+ $that = BigDecimal::of($that);
+
+ if ($that->isZero()) {
+ throw DivisionByZeroException::divisionByZero();
+ }
+
+ if ($scale === null) {
+ $scale = $this->scale;
+ } elseif ($scale < 0) {
+ throw new \InvalidArgumentException('Scale cannot be negative.');
+ }
+
+ if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) {
+ return $this;
+ }
+
+ $p = $this->valueWithMinScale($that->scale + $scale);
+ $q = $that->valueWithMinScale($this->scale - $scale);
+
+ $result = Calculator::get()->divRound($p, $q, $roundingMode);
+
+ return new BigDecimal($result, $scale);
+ }
+
+ /**
+ * Returns the exact result of the division of this number by the given one.
+ *
+ * The scale of the result is automatically calculated to fit all the fraction digits.
+ *
+ * @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
+ {
+ $that = BigDecimal::of($that);
+
+ if ($that->value === '0') {
+ throw DivisionByZeroException::divisionByZero();
+ }
+
+ [$a, $b] = $this->scaleValues($this, $that);
+
+ $d = \rtrim($b, '0');
+ $scale = \strlen($b) - \strlen($d);
+
+ $calculator = Calculator::get();
+
+ foreach ([5, 2] as $prime) {
+ for (;;) {
+ $lastDigit = (int) $d[-1];
+
+ if ($lastDigit % $prime !== 0) {
+ break;
+ }
+
+ $d = $calculator->divQ($d, (string) $prime);
+ $scale++;
+ }
+ }
+
+ return $this->dividedBy($that, $scale)->stripTrailingZeros();
+ }
+
+ /**
+ * Returns this number exponentiated to the given value.
+ *
+ * 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
+ {
+ if ($exponent === 0) {
+ return BigDecimal::one();
+ }
+
+ if ($exponent === 1) {
+ return $this;
+ }
+
+ if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {
+ throw new \InvalidArgumentException(\sprintf(
+ 'The exponent %d is not in the range 0 to %d.',
+ $exponent,
+ Calculator::MAX_POWER
+ ));
+ }
+
+ return new BigDecimal(Calculator::get()->pow($this->value, $exponent), $this->scale * $exponent);
+ }
+
+ /**
+ * Returns the quotient of the division of this number by this 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
+ {
+ $that = BigDecimal::of($that);
+
+ if ($that->isZero()) {
+ throw DivisionByZeroException::divisionByZero();
+ }
+
+ $p = $this->valueWithMinScale($that->scale);
+ $q = $that->valueWithMinScale($this->scale);
+
+ $quotient = Calculator::get()->divQ($p, $q);
+
+ return new BigDecimal($quotient, 0);
+ }
+
+ /**
+ * Returns the remainder of the division of this number by this 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
+ {
+ $that = BigDecimal::of($that);
+
+ if ($that->isZero()) {
+ throw DivisionByZeroException::divisionByZero();
+ }
+
+ $p = $this->valueWithMinScale($that->scale);
+ $q = $that->valueWithMinScale($this->scale);
+
+ $remainder = Calculator::get()->divR($p, $q);
+
+ $scale = $this->scale > $that->scale ? $this->scale : $that->scale;
+
+ return new BigDecimal($remainder, $scale);
+ }
+
+ /**
+ * Returns the quotient and remainder of the division of this number by the given one.
+ *
+ * The quotient has a scale of `0`, and 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[] An array containing the quotient and the remainder.
+ *
+ * @throws MathException If the divisor is not a valid decimal number, or is zero.
+ */
+ public function quotientAndRemainder($that) : array
+ {
+ $that = BigDecimal::of($that);
+
+ if ($that->isZero()) {
+ throw DivisionByZeroException::divisionByZero();
+ }
+
+ $p = $this->valueWithMinScale($that->scale);
+ $q = $that->valueWithMinScale($this->scale);
+
+ [$quotient, $remainder] = Calculator::get()->divQR($p, $q);
+
+ $scale = $this->scale > $that->scale ? $this->scale : $that->scale;
+
+ $quotient = new BigDecimal($quotient, 0);
+ $remainder = new BigDecimal($remainder, $scale);
+
+ return [$quotient, $remainder];
+ }
+
+ /**
+ * 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.
+ */
+ public function sqrt(int $scale) : BigDecimal
+ {
+ if ($scale < 0) {
+ throw new \InvalidArgumentException('Scale cannot be negative.');
+ }
+
+ if ($this->value === '0') {
+ return new BigDecimal('0', $scale);
+ }
+
+ if ($this->value[0] === '-') {
+ throw new NegativeNumberException('Cannot calculate the square root of a negative number.');
+ }
+
+ $value = $this->value;
+ $addDigits = 2 * $scale - $this->scale;
+
+ if ($addDigits > 0) {
+ // add zeros
+ $value .= \str_repeat('0', $addDigits);
+ } elseif ($addDigits < 0) {
+ // trim digits
+ if (-$addDigits >= \strlen($this->value)) {
+ // requesting a scale too low, will always yield a zero result
+ return new BigDecimal('0', $scale);
+ }
+
+ $value = \substr($value, 0, $addDigits);
+ }
+
+ $value = Calculator::get()->sqrt($value);
+
+ return new BigDecimal($value, $scale);
+ }
+
+ /**
+ * 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
+ {
+ if ($n === 0) {
+ return $this;
+ }
+
+ if ($n < 0) {
+ return $this->withPointMovedRight(-$n);
+ }
+
+ return new BigDecimal($this->value, $this->scale + $n);
+ }
+
+ /**
+ * 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
+ {
+ if ($n === 0) {
+ return $this;
+ }
+
+ if ($n < 0) {
+ return $this->withPointMovedLeft(-$n);
+ }
+
+ $value = $this->value;
+ $scale = $this->scale - $n;
+
+ if ($scale < 0) {
+ if ($value !== '0') {
+ $value .= \str_repeat('0', -$scale);
+ }
+ $scale = 0;
+ }
+
+ return new BigDecimal($value, $scale);
+ }
+
+ /**
+ * Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part.
+ *
+ * @return BigDecimal
+ */
+ public function stripTrailingZeros() : BigDecimal
+ {
+ if ($this->scale === 0) {
+ return $this;
+ }
+
+ $trimmedValue = \rtrim($this->value, '0');
+
+ if ($trimmedValue === '') {
+ return BigDecimal::zero();
+ }
+
+ $trimmableZeros = \strlen($this->value) - \strlen($trimmedValue);
+
+ if ($trimmableZeros === 0) {
+ return $this;
+ }
+
+ if ($trimmableZeros > $this->scale) {
+ $trimmableZeros = $this->scale;
+ }
+
+ $value = \substr($this->value, 0, -$trimmableZeros);
+ $scale = $this->scale - $trimmableZeros;
+
+ return new BigDecimal($value, $scale);
+ }
+
+ /**
+ * Returns the absolute value of this number.
+ *
+ * @return BigDecimal
+ */
+ public function abs() : BigDecimal
+ {
+ return $this->isNegative() ? $this->negated() : $this;
+ }
+
+ /**
+ * 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
+ {
+ $that = BigNumber::of($that);
+
+ if ($that instanceof BigInteger) {
+ $that = $that->toBigDecimal();
+ }
+
+ if ($that instanceof BigDecimal) {
+ [$a, $b] = $this->scaleValues($this, $that);
+
+ return Calculator::get()->cmp($a, $b);
+ }
+
+ return - $that->compareTo($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ 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 int
+ */
+ public function getScale() : int
+ {
+ return $this->scale;
+ }
+
+ /**
+ * Returns a string representing the integral part of this decimal number.
+ *
+ * Example: `-123.456` => `-123`.
+ *
+ * @return string
+ */
+ public function getIntegralPart() : string
+ {
+ if ($this->scale === 0) {
+ return $this->value;
+ }
+
+ $value = $this->getUnscaledValueWithLeadingZeros();
+
+ return \substr($value, 0, -$this->scale);
+ }
+
+ /**
+ * Returns a string representing the fractional part of this decimal number.
+ *
+ * If the scale is zero, an empty string is returned.
+ *
+ * Examples: `-123.456` => '456', `123` => ''.
+ *
+ * @return string
+ */
+ public function getFractionalPart() : string
+ {
+ if ($this->scale === 0) {
+ return '';
+ }
+
+ $value = $this->getUnscaledValueWithLeadingZeros();
+
+ return \substr($value, -$this->scale);
+ }
+
+ /**
+ * 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}
+ */
+ public function toBigInteger() : BigInteger
+ {
+ if ($this->scale === 0) {
+ $zeroScaleDecimal = $this;
+ } else {
+ $zeroScaleDecimal = $this->dividedBy(1, 0);
+ }
+
+ return BigInteger::create($zeroScaleDecimal->value);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toBigDecimal() : BigDecimal
+ {
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toBigRational() : BigRational
+ {
+ $numerator = BigInteger::create($this->value);
+ $denominator = BigInteger::create('1' . \str_repeat('0', $this->scale));
+
+ return BigRational::create($numerator, $denominator, false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
+ {
+ if ($scale === $this->scale) {
+ return $this;
+ }
+
+ return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toInt() : int
+ {
+ return $this->toBigInteger()->toInt();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toFloat() : float
+ {
+ return (float) (string) $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString() : string
+ {
+ if ($this->scale === 0) {
+ return $this->value;
+ }
+
+ $value = $this->getUnscaledValueWithLeadingZeros();
+
+ return \substr($value, 0, -$this->scale) . '.' . \substr($value, -$this->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
+ *
+ * @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{0: string, 1: string} The scaled integer values of $x and $y.
+ */
+ private function scaleValues(BigDecimal $x, BigDecimal $y) : array
+ {
+ $a = $x->value;
+ $b = $y->value;
+
+ if ($b !== '0' && $x->scale > $y->scale) {
+ $b .= \str_repeat('0', $x->scale - $y->scale);
+ } elseif ($a !== '0' && $x->scale < $y->scale) {
+ $a .= \str_repeat('0', $y->scale - $x->scale);
+ }
+
+ return [$a, $b];
+ }
+
+ /**
+ * @param int $scale
+ *
+ * @return string
+ */
+ private function valueWithMinScale(int $scale) : string
+ {
+ $value = $this->value;
+
+ if ($this->value !== '0' && $scale > $this->scale) {
+ $value .= \str_repeat('0', $scale - $this->scale);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Adds leading zeros if necessary to the unscaled value to represent the full decimal number.
+ *
+ * @return string
+ */
+ private function getUnscaledValueWithLeadingZeros() : string
+ {
+ $value = $this->value;
+ $targetLength = $this->scale + 1;
+ $negative = ($value[0] === '-');
+ $length = \strlen($value);
+
+ if ($negative) {
+ $length--;
+ }
+
+ if ($length >= $targetLength) {
+ return $this->value;
+ }
+
+ if ($negative) {
+ $value = \substr($value, 1);
+ }
+
+ $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT);
+
+ if ($negative) {
+ $value = '-' . $value;
+ }
+
+ return $value;
+ }
+}
diff --git a/brick/math/src/BigInteger.php b/brick/math/src/BigInteger.php
new file mode 100644
index 000000000..5607560e5
--- /dev/null
+++ b/brick/math/src/BigInteger.php
@@ -0,0 +1,1166 @@
+value = $value;
+ }
+
+ /**
+ * 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
+ {
+ return parent::of($value)->toBigInteger();
+ }
+
+ /**
+ * Parses a string containing an integer in an arbitrary base.
+ *
+ * @deprecated will be removed in version 0.9 - use fromBase() instead
+ *
+ * The string can optionally be prefixed with the `+` or `-` sign.
+ * For bases greater than 10, both uppercase and lowercase letters are allowed.
+ *
+ * @param string $number The number to parse.
+ * @param int $base The base of the number, between 2 and 36.
+ *
+ * @return BigInteger
+ *
+ * @throws \InvalidArgumentException If the number is invalid or the base is out of range.
+ */
+ public static function parse(string $number, int $base = 10) : BigInteger
+ {
+ try {
+ return self::fromBase($number, $base);
+ } catch (NumberFormatException $e) {
+ throw new \InvalidArgumentException($e->getMessage(), 0, $e);
+ }
+ }
+
+ /**
+ * Creates a number from a string in a given base.
+ *
+ * The string can optionally be prefixed with the `+` or `-` sign.
+ *
+ * Bases greater than 36 are not supported by this method, as there is no clear consensus on which of the lowercase
+ * or uppercase characters should come first. Instead, this method accepts any base up to 36, and does not
+ * differentiate lowercase and uppercase characters, which are considered equal.
+ *
+ * For bases greater than 36, and/or custom alphabets, use the fromArbitraryBase() method.
+ *
+ * @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.
+ *
+ * @psalm-pure
+ */
+ public static function fromBase(string $number, int $base) : BigInteger
+ {
+ if ($number === '') {
+ throw new NumberFormatException('The number cannot be empty.');
+ }
+
+ if ($base < 2 || $base > 36) {
+ throw new \InvalidArgumentException(\sprintf('Base %d is not in range 2 to 36.', $base));
+ }
+
+ if ($number[0] === '-') {
+ $sign = '-';
+ $number = \substr($number, 1);
+ } elseif ($number[0] === '+') {
+ $sign = '';
+ $number = \substr($number, 1);
+ } else {
+ $sign = '';
+ }
+
+ if ($number === '') {
+ throw new NumberFormatException('The number cannot be empty.');
+ }
+
+ $number = \ltrim($number, '0');
+
+ if ($number === '') {
+ // The result will be the same in any base, avoid further calculation.
+ return BigInteger::zero();
+ }
+
+ if ($number === '1') {
+ // The result will be the same in any base, avoid further calculation.
+ return new BigInteger($sign . '1');
+ }
+
+ $pattern = '/[^' . \substr(Calculator::ALPHABET, 0, $base) . ']/';
+
+ if (\preg_match($pattern, \strtolower($number), $matches) === 1) {
+ throw new NumberFormatException(\sprintf('"%s" is not a valid character in base %d.', $matches[0], $base));
+ }
+
+ if ($base === 10) {
+ // The number is usable as is, avoid further calculation.
+ return new BigInteger($sign . $number);
+ }
+
+ $result = Calculator::get()->fromBase($number, $base);
+
+ return new BigInteger($sign . $result);
+ }
+
+ /**
+ * Parses a string containing an integer in an arbitrary base, using a custom alphabet.
+ *
+ * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers.
+ *
+ * @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.
+ *
+ * @psalm-pure
+ */
+ public static function fromArbitraryBase(string $number, string $alphabet) : BigInteger
+ {
+ if ($number === '') {
+ throw new NumberFormatException('The number cannot be empty.');
+ }
+
+ $base = \strlen($alphabet);
+
+ if ($base < 2) {
+ throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');
+ }
+
+ $pattern = '/[^' . \preg_quote($alphabet, '/') . ']/';
+
+ if (\preg_match($pattern, $number, $matches) === 1) {
+ throw NumberFormatException::charNotInAlphabet($matches[0]);
+ }
+
+ $number = Calculator::get()->fromArbitraryBase($number, $alphabet, $base);
+
+ return new BigInteger($number);
+ }
+
+ /**
+ * Translates a string of bytes containing the binary representation of a BigInteger into a BigInteger.
+ *
+ * The input string is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element.
+ *
+ * If `$signed` is true, the input is assumed to be in two's-complement representation, and the leading bit is
+ * interpreted as a sign bit. If `$signed` is false, the input is interpreted as an unsigned number, and the
+ * resulting BigInteger will always be positive or zero.
+ *
+ * This method can be used to retrieve a number exported by `toBytes()`, as long as the `$signed` flags match.
+ *
+ * @param string $value The byte string.
+ * @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
+ {
+ if ($value === '') {
+ throw new NumberFormatException('The byte string must not be empty.');
+ }
+
+ $twosComplement = false;
+
+ if ($signed) {
+ $x = ord($value[0]);
+
+ if (($twosComplement = ($x >= 0x80))) {
+ $value = ~$value;
+ }
+ }
+
+ $number = self::fromBase(bin2hex($value), 16);
+
+ if ($twosComplement) {
+ return $number->plus(1)->negated();
+ }
+
+ return $number;
+ }
+
+ /**
+ * Generates a pseudo-random number in the range 0 to 2^numBits - 1.
+ *
+ * Using the default random bytes generator, this method is suitable for cryptographic use.
+ *
+ * @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
+ {
+ if ($numBits < 0) {
+ throw new \InvalidArgumentException('The number of bits cannot be negative.');
+ }
+
+ if ($numBits === 0) {
+ return BigInteger::zero();
+ }
+
+ if ($randomBytesGenerator === null) {
+ $randomBytesGenerator = 'random_bytes';
+ }
+
+ $byteLength = intdiv($numBits - 1, 8) + 1;
+
+ $extraBits = ($byteLength * 8 - $numBits);
+ $bitmask = chr(0xFF >> $extraBits);
+
+ $randomBytes = $randomBytesGenerator($byteLength);
+ $randomBytes[0] = $randomBytes[0] & $bitmask;
+
+ return self::fromBytes($randomBytes, false);
+ }
+
+ /**
+ * Generates a pseudo-random number between `$min` and `$max`.
+ *
+ * Using the default random bytes generator, this method is suitable for cryptographic use.
+ *
+ * @param BigNumber|int|float|string $min The lower bound. Must be convertible to a BigInteger.
+ * @param BigNumber|int|float|string $max The upper bound. Must be convertible to a BigInteger.
+ * @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 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
+ {
+ $min = BigInteger::of($min);
+ $max = BigInteger::of($max);
+
+ if ($min->isGreaterThan($max)) {
+ throw new MathException('$min cannot be greater than $max.');
+ }
+
+ if ($min->isEqualTo($max)) {
+ return $min;
+ }
+
+ $diff = $max->minus($min);
+ $bitLength = $diff->getBitLength();
+
+ // try until the number is in range (50% to 100% chance of success)
+ do {
+ $randomNumber = self::randomBits($bitLength, $randomBytesGenerator);
+ } while ($randomNumber->isGreaterThan($diff));
+
+ return $randomNumber->plus($min);
+ }
+
+ /**
+ * Returns a BigInteger representing zero.
+ *
+ * @return BigInteger
+ *
+ * @psalm-pure
+ */
+ public static function zero() : BigInteger
+ {
+ /** @psalm-suppress ImpureStaticVariable */
+ static $zero;
+
+ if ($zero === null) {
+ $zero = new BigInteger('0');
+ }
+
+ return $zero;
+ }
+
+ /**
+ * Returns a BigInteger representing one.
+ *
+ * @return BigInteger
+ *
+ * @psalm-pure
+ */
+ public static function one() : BigInteger
+ {
+ /** @psalm-suppress ImpureStaticVariable */
+ static $one;
+
+ if ($one === null) {
+ $one = new BigInteger('1');
+ }
+
+ return $one;
+ }
+
+ /**
+ * Returns a BigInteger representing ten.
+ *
+ * @return BigInteger
+ *
+ * @psalm-pure
+ */
+ public static function ten() : BigInteger
+ {
+ /** @psalm-suppress ImpureStaticVariable */
+ static $ten;
+
+ if ($ten === null) {
+ $ten = new BigInteger('10');
+ }
+
+ return $ten;
+ }
+
+ /**
+ * 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
+ {
+ $that = BigInteger::of($that);
+
+ if ($that->value === '0') {
+ return $this;
+ }
+
+ if ($this->value === '0') {
+ return $that;
+ }
+
+ $value = Calculator::get()->add($this->value, $that->value);
+
+ return new BigInteger($value);
+ }
+
+ /**
+ * Returns the difference of this number and the given one.
+ *
+ * @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
+ {
+ $that = BigInteger::of($that);
+
+ if ($that->value === '0') {
+ return $this;
+ }
+
+ $value = Calculator::get()->sub($this->value, $that->value);
+
+ return new BigInteger($value);
+ }
+
+ /**
+ * Returns the product of this number and the given one.
+ *
+ * @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
+ {
+ $that = BigInteger::of($that);
+
+ if ($that->value === '1') {
+ return $this;
+ }
+
+ if ($this->value === '1') {
+ return $that;
+ }
+
+ $value = Calculator::get()->mul($this->value, $that->value);
+
+ return new BigInteger($value);
+ }
+
+ /**
+ * 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.
+ *
+ * @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
+ {
+ $that = BigInteger::of($that);
+
+ if ($that->value === '1') {
+ return $this;
+ }
+
+ if ($that->value === '0') {
+ throw DivisionByZeroException::divisionByZero();
+ }
+
+ $result = Calculator::get()->divRound($this->value, $that->value, $roundingMode);
+
+ return new BigInteger($result);
+ }
+
+ /**
+ * 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
+ {
+ if ($exponent === 0) {
+ return BigInteger::one();
+ }
+
+ if ($exponent === 1) {
+ return $this;
+ }
+
+ if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {
+ throw new \InvalidArgumentException(\sprintf(
+ 'The exponent %d is not in the range 0 to %d.',
+ $exponent,
+ Calculator::MAX_POWER
+ ));
+ }
+
+ return new BigInteger(Calculator::get()->pow($this->value, $exponent));
+ }
+
+ /**
+ * Returns the quotient of the division of this number by the given one.
+ *
+ * @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
+ {
+ $that = BigInteger::of($that);
+
+ if ($that->value === '1') {
+ return $this;
+ }
+
+ if ($that->value === '0') {
+ throw DivisionByZeroException::divisionByZero();
+ }
+
+ $quotient = Calculator::get()->divQ($this->value, $that->value);
+
+ return new BigInteger($quotient);
+ }
+
+ /**
+ * Returns the remainder of the division of this number by the given one.
+ *
+ * The remainder, when non-zero, has the same sign as the dividend.
+ *
+ * @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
+ {
+ $that = BigInteger::of($that);
+
+ if ($that->value === '1') {
+ return BigInteger::zero();
+ }
+
+ if ($that->value === '0') {
+ throw DivisionByZeroException::divisionByZero();
+ }
+
+ $remainder = Calculator::get()->divR($this->value, $that->value);
+
+ return new BigInteger($remainder);
+ }
+
+ /**
+ * Returns the quotient and remainder of the division of this number by the given one.
+ *
+ * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
+ *
+ * @return BigInteger[] An array containing the quotient and the remainder.
+ *
+ * @throws DivisionByZeroException If the divisor is zero.
+ */
+ public function quotientAndRemainder($that) : array
+ {
+ $that = BigInteger::of($that);
+
+ if ($that->value === '0') {
+ throw DivisionByZeroException::divisionByZero();
+ }
+
+ [$quotient, $remainder] = Calculator::get()->divQR($this->value, $that->value);
+
+ return [
+ new BigInteger($quotient),
+ new BigInteger($remainder)
+ ];
+ }
+
+ /**
+ * Returns the modulo of this number and the given one.
+ *
+ * The modulo operation yields the same result as the remainder operation when both operands are of the same sign,
+ * and may differ when signs are different.
+ *
+ * The result of the modulo operation, when non-zero, has the same sign as the divisor.
+ *
+ * @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
+ {
+ $that = BigInteger::of($that);
+
+ if ($that->value === '0') {
+ throw DivisionByZeroException::modulusMustNotBeZero();
+ }
+
+ $value = Calculator::get()->mod($this->value, $that->value);
+
+ return new BigInteger($value);
+ }
+
+ /**
+ * 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
+ * is not relatively prime to m).
+ */
+ public function modInverse(BigInteger $m) : BigInteger
+ {
+ if ($m->value === '0') {
+ throw DivisionByZeroException::modulusMustNotBeZero();
+ }
+
+ if ($m->isNegative()) {
+ throw new NegativeNumberException('Modulus must not be negative.');
+ }
+
+ if ($m->value === '1') {
+ return BigInteger::zero();
+ }
+
+ $value = Calculator::get()->modInverse($this->value, $m->value);
+
+ if ($value === null) {
+ throw new MathException('Unable to compute the modInverse for the given modulus.');
+ }
+
+ return new BigInteger($value);
+ }
+
+ /**
+ * Returns this number raised into power with modulo.
+ *
+ * This operation only works on positive numbers.
+ *
+ * @param BigNumber|int|float|string $exp The positive exponent.
+ * @param BigNumber|int|float|string $mod The modulus. Must not be zero.
+ *
+ * @return BigInteger
+ *
+ * @throws NegativeNumberException If any of the operands is negative.
+ * @throws DivisionByZeroException If the modulus is zero.
+ */
+ public function modPow($exp, $mod) : BigInteger
+ {
+ $exp = BigInteger::of($exp);
+ $mod = BigInteger::of($mod);
+
+ if ($this->isNegative() || $exp->isNegative() || $mod->isNegative()) {
+ throw new NegativeNumberException('The operands cannot be negative.');
+ }
+
+ if ($mod->isZero()) {
+ throw DivisionByZeroException::modulusMustNotBeZero();
+ }
+
+ $result = Calculator::get()->modPow($this->value, $exp->value, $mod->value);
+
+ return new BigInteger($result);
+ }
+
+ /**
+ * Returns this number raised into power with modulo.
+ *
+ * @deprecated Use modPow() instead.
+ *
+ * @param BigNumber|int|float|string $exp The positive exponent.
+ * @param BigNumber|int|float|string $mod The modulus. Must not be zero.
+ *
+ * @return BigInteger
+ *
+ * @throws NegativeNumberException If any of the operands is negative.
+ * @throws DivisionByZeroException If the modulus is zero.
+ */
+ public function powerMod($exp, $mod) : BigInteger
+ {
+ return $this->modPow($exp, $mod);
+ }
+
+ /**
+ * Returns the greatest common divisor of this number and the given one.
+ *
+ * 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
+ {
+ $that = BigInteger::of($that);
+
+ if ($that->value === '0' && $this->value[0] !== '-') {
+ return $this;
+ }
+
+ if ($this->value === '0' && $that->value[0] !== '-') {
+ return $that;
+ }
+
+ $value = Calculator::get()->gcd($this->value, $that->value);
+
+ return new BigInteger($value);
+ }
+
+ /**
+ * Returns the integer square root number of this number, rounded down.
+ *
+ * The result is the largest x such that x² ≤ n.
+ *
+ * @return BigInteger
+ *
+ * @throws NegativeNumberException If this number is negative.
+ */
+ public function sqrt() : BigInteger
+ {
+ if ($this->value[0] === '-') {
+ throw new NegativeNumberException('Cannot calculate the square root of a negative number.');
+ }
+
+ $value = Calculator::get()->sqrt($this->value);
+
+ return new BigInteger($value);
+ }
+
+ /**
+ * Returns the absolute value of this number.
+ *
+ * @return BigInteger
+ */
+ public function abs() : BigInteger
+ {
+ return $this->isNegative() ? $this->negated() : $this;
+ }
+
+ /**
+ * Returns the inverse of this number.
+ *
+ * @return BigInteger
+ */
+ public function negated() : BigInteger
+ {
+ return new BigInteger(Calculator::get()->neg($this->value));
+ }
+
+ /**
+ * Returns the integer bitwise-and combined with another integer.
+ *
+ * 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
+ {
+ $that = BigInteger::of($that);
+
+ return new BigInteger(Calculator::get()->and($this->value, $that->value));
+ }
+
+ /**
+ * Returns the integer bitwise-or combined with another integer.
+ *
+ * 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
+ {
+ $that = BigInteger::of($that);
+
+ return new BigInteger(Calculator::get()->or($this->value, $that->value));
+ }
+
+ /**
+ * Returns the integer bitwise-xor combined with another integer.
+ *
+ * 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
+ {
+ $that = BigInteger::of($that);
+
+ return new BigInteger(Calculator::get()->xor($this->value, $that->value));
+ }
+
+ /**
+ * 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
+ {
+ if ($distance === 0) {
+ return $this;
+ }
+
+ if ($distance < 0) {
+ return $this->shiftedRight(- $distance);
+ }
+
+ return $this->multipliedBy(BigInteger::of(2)->power($distance));
+ }
+
+ /**
+ * 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
+ {
+ if ($distance === 0) {
+ return $this;
+ }
+
+ if ($distance < 0) {
+ return $this->shiftedLeft(- $distance);
+ }
+
+ $operand = BigInteger::of(2)->power($distance);
+
+ if ($this->isPositiveOrZero()) {
+ return $this->quotient($operand);
+ }
+
+ return $this->dividedBy($operand, RoundingMode::UP);
+ }
+
+ /**
+ * Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit.
+ *
+ * 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
+ {
+ if ($this->value === '0') {
+ return 0;
+ }
+
+ if ($this->isNegative()) {
+ return $this->abs()->minus(1)->getBitLength();
+ }
+
+ return strlen($this->toBase(2));
+ }
+
+ /**
+ * 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
+ {
+ $n = $this;
+ $bitLength = $this->getBitLength();
+
+ for ($i = 0; $i <= $bitLength; $i++) {
+ if ($n->isOdd()) {
+ return $i;
+ }
+
+ $n = $n->shiftedRight(1);
+ }
+
+ return -1;
+ }
+
+ /**
+ * Returns whether this number is even.
+ *
+ * @return bool
+ */
+ public function isEven() : bool
+ {
+ return in_array($this->value[-1], ['0', '2', '4', '6', '8'], true);
+ }
+
+ /**
+ * Returns whether this number is odd.
+ *
+ * @return bool
+ */
+ public function isOdd() : bool
+ {
+ return in_array($this->value[-1], ['1', '3', '5', '7', '9'], true);
+ }
+
+ /**
+ * Returns true if and only if the designated bit is set.
+ *
+ * Computes ((this & (1<shiftedRight($n)->isOdd();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function compareTo($that) : int
+ {
+ $that = BigNumber::of($that);
+
+ if ($that instanceof BigInteger) {
+ return Calculator::get()->cmp($this->value, $that->value);
+ }
+
+ return - $that->compareTo($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSign() : int
+ {
+ return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toBigInteger() : BigInteger
+ {
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toBigDecimal() : BigDecimal
+ {
+ return BigDecimal::create($this->value);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toBigRational() : BigRational
+ {
+ return BigRational::create($this, BigInteger::one(), false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
+ {
+ return $this->toBigDecimal()->toScale($scale, $roundingMode);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toInt() : int
+ {
+ $intValue = (int) $this->value;
+
+ if ($this->value !== (string) $intValue) {
+ throw IntegerOverflowException::toIntOverflow($this);
+ }
+
+ return $intValue;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toFloat() : float
+ {
+ return (float) $this->value;
+ }
+
+ /**
+ * Returns a string representation of this number in the given base.
+ *
+ * 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
+ {
+ if ($base === 10) {
+ return $this->value;
+ }
+
+ if ($base < 2 || $base > 36) {
+ throw new \InvalidArgumentException(\sprintf('Base %d is out of range [2, 36]', $base));
+ }
+
+ return Calculator::get()->toBase($this->value, $base);
+ }
+
+ /**
+ * Returns a string representation of this number in an arbitrary base with a custom alphabet.
+ *
+ * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers;
+ * a NegativeNumberException will be thrown when attempting to call this method on a negative number.
+ *
+ * @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.
+ */
+ public function toArbitraryBase(string $alphabet) : string
+ {
+ $base = \strlen($alphabet);
+
+ if ($base < 2) {
+ throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');
+ }
+
+ if ($this->value[0] === '-') {
+ throw new NegativeNumberException(__FUNCTION__ . '() does not support negative numbers.');
+ }
+
+ return Calculator::get()->toArbitraryBase($this->value, $alphabet, $base);
+ }
+
+ /**
+ * Returns a string of bytes containing the binary representation of this BigInteger.
+ *
+ * The string is in big-endian byte-order: the most significant byte is in the zeroth element.
+ *
+ * If `$signed` is true, the output will be in two's-complement representation, and a sign bit will be prepended to
+ * the output. If `$signed` is false, no sign bit will be prepended, and this method will throw an exception if the
+ * number is negative.
+ *
+ * The string will contain the minimum number of bytes required to represent this BigInteger, including a sign bit
+ * if `$signed` is true.
+ *
+ * This representation is compatible with the `fromBytes()` factory method, as long as the `$signed` flags match.
+ *
+ * @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
+ {
+ if (! $signed && $this->isNegative()) {
+ throw new NegativeNumberException('Cannot convert a negative number to a byte string when $signed is false.');
+ }
+
+ $hex = $this->abs()->toBase(16);
+
+ if (strlen($hex) % 2 !== 0) {
+ $hex = '0' . $hex;
+ }
+
+ $baseHexLength = strlen($hex);
+
+ if ($signed) {
+ if ($this->isNegative()) {
+ $hex = bin2hex(~hex2bin($hex));
+ $hex = self::fromBase($hex, 16)->plus(1)->toBase(16);
+
+ $hexLength = strlen($hex);
+
+ if ($hexLength < $baseHexLength) {
+ $hex = str_repeat('0', $baseHexLength - $hexLength) . $hex;
+ }
+
+ if ($hex[0] < '8') {
+ $hex = 'FF' . $hex;
+ }
+ } else {
+ if ($hex[0] >= '8') {
+ $hex = '00' . $hex;
+ }
+ }
+ }
+
+ return hex2bin($hex);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString() : string
+ {
+ return $this->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
+ *
+ * @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;
+ }
+}
diff --git a/brick/math/src/BigNumber.php b/brick/math/src/BigNumber.php
new file mode 100644
index 000000000..d2d97a7c7
--- /dev/null
+++ b/brick/math/src/BigNumber.php
@@ -0,0 +1,528 @@
+[\-\+]?[0-9]+)' .
+ '(?:' .
+ '(?:' .
+ '(?:\.(?[0-9]+))?' .
+ '(?:[eE](?[\-\+]?[0-9]+))?' .
+ ')' . '|' . '(?:' .
+ '(?:\/(?[0-9]+))?' .
+ ')' .
+ ')?' .
+ '$/';
+
+ /**
+ * Creates a BigNumber of the given value.
+ *
+ * The concrete return type is dependent on the given value, with the following rules:
+ *
+ * - BigNumber instances are returned as is
+ * - integer numbers are returned as BigInteger
+ * - floating point numbers are converted to a string then parsed as such
+ * - strings containing a `/` character are returned as BigRational
+ * - 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.
+ *
+ * @psalm-pure
+ */
+ public static function of($value) : BigNumber
+ {
+ if ($value instanceof BigNumber) {
+ return $value;
+ }
+
+ if (\is_int($value)) {
+ return new BigInteger((string) $value);
+ }
+
+ if (\is_float($value)) {
+ $value = self::floatToString($value);
+ } else {
+ $value = (string) $value;
+ }
+
+ if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) {
+ throw new NumberFormatException(\sprintf('The given value "%s" does not represent a valid number.', $value));
+ }
+
+ if (isset($matches['denominator'])) {
+ $numerator = self::cleanUp($matches['integral']);
+ $denominator = \ltrim($matches['denominator'], '0');
+
+ if ($denominator === '') {
+ throw DivisionByZeroException::denominatorMustNotBeZero();
+ }
+
+ return new BigRational(new BigInteger($numerator), new BigInteger($denominator), false);
+ }
+
+ if (isset($matches['fractional']) || isset($matches['exponent'])) {
+ $fractional = isset($matches['fractional']) ? $matches['fractional'] : '';
+ $exponent = isset($matches['exponent']) ? (int) $matches['exponent'] : 0;
+
+ $unscaledValue = self::cleanUp($matches['integral'] . $fractional);
+
+ $scale = \strlen($fractional) - $exponent;
+
+ if ($scale < 0) {
+ if ($unscaledValue !== '0') {
+ $unscaledValue .= \str_repeat('0', - $scale);
+ }
+ $scale = 0;
+ }
+
+ return new BigDecimal($unscaledValue, $scale);
+ }
+
+ $integral = self::cleanUp($matches['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.
+ *
+ * @internal
+ *
+ * @param mixed ...$args The arguments to the constructor.
+ *
+ * @return static
+ *
+ * @psalm-pure
+ */
+ protected static function create(... $args) : BigNumber
+ {
+ /** @psalm-suppress TooManyArguments */
+ return new static(... $args);
+ }
+
+ /**
+ * Returns the minimum of the given values.
+ *
+ * @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-pure
+ */
+ public static function min(...$values) : BigNumber
+ {
+ $min = null;
+
+ foreach ($values as $value) {
+ $value = static::of($value);
+
+ if ($min === null || $value->isLessThan($min)) {
+ $min = $value;
+ }
+ }
+
+ if ($min === null) {
+ throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
+ }
+
+ return $min;
+ }
+
+ /**
+ * Returns the maximum of the given values.
+ *
+ * @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-pure
+ */
+ public static function max(...$values) : BigNumber
+ {
+ $max = null;
+
+ foreach ($values as $value) {
+ $value = static::of($value);
+
+ if ($max === null || $value->isGreaterThan($max)) {
+ $max = $value;
+ }
+ }
+
+ if ($max === null) {
+ throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
+ }
+
+ return $max;
+ }
+
+ /**
+ * Returns the sum of the given values.
+ *
+ * @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-pure
+ */
+ public static function sum(...$values) : BigNumber
+ {
+ /** @var BigNumber|null $sum */
+ $sum = null;
+
+ foreach ($values as $value) {
+ $value = static::of($value);
+
+ if ($sum === null) {
+ $sum = $value;
+ } else {
+ $sum = self::add($sum, $value);
+ }
+ }
+
+ if ($sum === null) {
+ throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
+ }
+
+ return $sum;
+ }
+
+ /**
+ * Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException.
+ *
+ * @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to
+ * concrete classes the responsibility to perform the addition themselves or delegate it to the given number,
+ * 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
+ {
+ if ($a instanceof BigRational) {
+ return $a->plus($b);
+ }
+
+ if ($b instanceof BigRational) {
+ return $b->plus($a);
+ }
+
+ if ($a instanceof BigDecimal) {
+ return $a->plus($b);
+ }
+
+ if ($b instanceof BigDecimal) {
+ return $b->plus($a);
+ }
+
+ /** @var BigInteger $a */
+
+ return $a->plus($b);
+ }
+
+ /**
+ * Removes optional leading zeros and + sign from the given number.
+ *
+ * @param string $number The number, validated as a non-empty string of digits with optional sign.
+ *
+ * @return string
+ *
+ * @psalm-pure
+ */
+ private static function cleanUp(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;
+ }
+
+ /**
+ * Checks if this number is equal to the given one.
+ *
+ * @param BigNumber|int|float|string $that
+ *
+ * @return bool
+ */
+ public function isEqualTo($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
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ return $this->compareTo($that) >= 0;
+ }
+
+ /**
+ * Checks if this number equals zero.
+ *
+ * @return bool
+ */
+ public function isZero() : bool
+ {
+ return $this->getSign() === 0;
+ }
+
+ /**
+ * Checks if this number is strictly negative.
+ *
+ * @return bool
+ */
+ public function isNegative() : bool
+ {
+ return $this->getSign() < 0;
+ }
+
+ /**
+ * Checks if this number is negative or zero.
+ *
+ * @return bool
+ */
+ public function isNegativeOrZero() : bool
+ {
+ return $this->getSign() <= 0;
+ }
+
+ /**
+ * Checks if this number is strictly positive.
+ *
+ * @return bool
+ */
+ public function isPositive() : bool
+ {
+ return $this->getSign() > 0;
+ }
+
+ /**
+ * Checks if this number is positive or zero.
+ *
+ * @return bool
+ */
+ public function isPositiveOrZero() : bool
+ {
+ return $this->getSign() >= 0;
+ }
+
+ /**
+ * Returns the sign of this number.
+ *
+ * @return int -1 if the number is negative, 0 if zero, 1 if positive.
+ */
+ abstract public function getSign() : int;
+
+ /**
+ * Compares this number to the given one.
+ *
+ * @param BigNumber|int|float|string $that
+ *
+ * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`.
+ *
+ * @throws MathException If the number is not valid.
+ */
+ abstract public function compareTo($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;
+
+ /**
+ * 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;
+
+ /**
+ * 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
+ *
+ * @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;
+
+ /**
+ * Returns the exact value of this number as a native integer.
+ *
+ * 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;
+
+ /**
+ * Returns an approximation of this number as a floating-point value.
+ *
+ * Note that this method can discard information as the precision of a floating-point value
+ * is inherently limited.
+ *
+ * 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;
+
+ /**
+ * Returns a string representation of this number.
+ *
+ * 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
+ {
+ return $this->__toString();
+ }
+}
diff --git a/brick/math/src/BigRational.php b/brick/math/src/BigRational.php
new file mode 100644
index 000000000..ff035c5c0
--- /dev/null
+++ b/brick/math/src/BigRational.php
@@ -0,0 +1,479 @@
+isZero()) {
+ throw DivisionByZeroException::denominatorMustNotBeZero();
+ }
+
+ if ($denominator->isNegative()) {
+ $numerator = $numerator->negated();
+ $denominator = $denominator->negated();
+ }
+ }
+
+ $this->numerator = $numerator;
+ $this->denominator = $denominator;
+ }
+
+ /**
+ * 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
+ {
+ return parent::of($value)->toBigRational();
+ }
+
+ /**
+ * Creates a BigRational out of a numerator and a denominator.
+ *
+ * If the denominator is negative, the signs of both the numerator and the denominator
+ * will be inverted to ensure that the denominator is always positive.
+ *
+ * @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
+ {
+ $numerator = BigInteger::of($numerator);
+ $denominator = BigInteger::of($denominator);
+
+ return new BigRational($numerator, $denominator, true);
+ }
+
+ /**
+ * Returns a BigRational representing zero.
+ *
+ * @return BigRational
+ *
+ * @psalm-pure
+ */
+ public static function zero() : BigRational
+ {
+ /** @psalm-suppress ImpureStaticVariable */
+ static $zero;
+
+ if ($zero === null) {
+ $zero = new BigRational(BigInteger::zero(), BigInteger::one(), false);
+ }
+
+ return $zero;
+ }
+
+ /**
+ * Returns a BigRational representing one.
+ *
+ * @return BigRational
+ *
+ * @psalm-pure
+ */
+ public static function one() : BigRational
+ {
+ /** @psalm-suppress ImpureStaticVariable */
+ static $one;
+
+ if ($one === null) {
+ $one = new BigRational(BigInteger::one(), BigInteger::one(), false);
+ }
+
+ return $one;
+ }
+
+ /**
+ * Returns a BigRational representing ten.
+ *
+ * @return BigRational
+ *
+ * @psalm-pure
+ */
+ public static function ten() : BigRational
+ {
+ /** @psalm-suppress ImpureStaticVariable */
+ static $ten;
+
+ if ($ten === null) {
+ $ten = new BigRational(BigInteger::ten(), BigInteger::one(), false);
+ }
+
+ return $ten;
+ }
+
+ /**
+ * @return BigInteger
+ */
+ public function getNumerator() : BigInteger
+ {
+ return $this->numerator;
+ }
+
+ /**
+ * @return BigInteger
+ */
+ public function getDenominator() : BigInteger
+ {
+ return $this->denominator;
+ }
+
+ /**
+ * Returns the quotient of the division of the numerator by the denominator.
+ *
+ * @return BigInteger
+ */
+ public function quotient() : BigInteger
+ {
+ return $this->numerator->quotient($this->denominator);
+ }
+
+ /**
+ * Returns the remainder of the division of the numerator by the denominator.
+ *
+ * @return BigInteger
+ */
+ public function remainder() : BigInteger
+ {
+ return $this->numerator->remainder($this->denominator);
+ }
+
+ /**
+ * Returns the quotient and remainder of the division of the numerator by the denominator.
+ *
+ * @return BigInteger[]
+ */
+ public function quotientAndRemainder() : array
+ {
+ return $this->numerator->quotientAndRemainder($this->denominator);
+ }
+
+ /**
+ * Returns the sum of this number and the given one.
+ *
+ * @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
+ {
+ $that = BigRational::of($that);
+
+ $numerator = $this->numerator->multipliedBy($that->denominator);
+ $numerator = $numerator->plus($that->numerator->multipliedBy($this->denominator));
+ $denominator = $this->denominator->multipliedBy($that->denominator);
+
+ return new BigRational($numerator, $denominator, false);
+ }
+
+ /**
+ * Returns the difference of this number and the given one.
+ *
+ * @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
+ {
+ $that = BigRational::of($that);
+
+ $numerator = $this->numerator->multipliedBy($that->denominator);
+ $numerator = $numerator->minus($that->numerator->multipliedBy($this->denominator));
+ $denominator = $this->denominator->multipliedBy($that->denominator);
+
+ return new BigRational($numerator, $denominator, false);
+ }
+
+ /**
+ * Returns the product of this number and the given one.
+ *
+ * @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
+ {
+ $that = BigRational::of($that);
+
+ $numerator = $this->numerator->multipliedBy($that->numerator);
+ $denominator = $this->denominator->multipliedBy($that->denominator);
+
+ return new BigRational($numerator, $denominator, false);
+ }
+
+ /**
+ * Returns the result of the division of this number by the given one.
+ *
+ * @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
+ {
+ $that = BigRational::of($that);
+
+ $numerator = $this->numerator->multipliedBy($that->denominator);
+ $denominator = $this->denominator->multipliedBy($that->numerator);
+
+ return new BigRational($numerator, $denominator, true);
+ }
+
+ /**
+ * 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
+ {
+ if ($exponent === 0) {
+ $one = BigInteger::one();
+
+ return new BigRational($one, $one, false);
+ }
+
+ if ($exponent === 1) {
+ return $this;
+ }
+
+ return new BigRational(
+ $this->numerator->power($exponent),
+ $this->denominator->power($exponent),
+ false
+ );
+ }
+
+ /**
+ * Returns the reciprocal of this BigRational.
+ *
+ * The reciprocal has the numerator and denominator swapped.
+ *
+ * @return BigRational
+ *
+ * @throws DivisionByZeroException If the numerator is zero.
+ */
+ public function reciprocal() : BigRational
+ {
+ return new BigRational($this->denominator, $this->numerator, true);
+ }
+
+ /**
+ * Returns the absolute value of this BigRational.
+ *
+ * @return BigRational
+ */
+ public function abs() : BigRational
+ {
+ return new BigRational($this->numerator->abs(), $this->denominator, false);
+ }
+
+ /**
+ * Returns the negated value of this BigRational.
+ *
+ * @return BigRational
+ */
+ public function negated() : BigRational
+ {
+ return new BigRational($this->numerator->negated(), $this->denominator, false);
+ }
+
+ /**
+ * Returns the simplified value of this BigRational.
+ *
+ * @return BigRational
+ */
+ public function simplified() : BigRational
+ {
+ $gcd = $this->numerator->gcd($this->denominator);
+
+ $numerator = $this->numerator->quotient($gcd);
+ $denominator = $this->denominator->quotient($gcd);
+
+ return new BigRational($numerator, $denominator, false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function compareTo($that) : int
+ {
+ return $this->minus($that)->getSign();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSign() : int
+ {
+ return $this->numerator->getSign();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toBigInteger() : BigInteger
+ {
+ $simplified = $this->simplified();
+
+ if (! $simplified->denominator->isEqualTo(1)) {
+ throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.');
+ }
+
+ return $simplified->numerator;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toBigDecimal() : BigDecimal
+ {
+ return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toBigRational() : BigRational
+ {
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
+ {
+ return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toInt() : int
+ {
+ return $this->toBigInteger()->toInt();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toFloat() : float
+ {
+ return $this->numerator->toFloat() / $this->denominator->toFloat();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString() : string
+ {
+ $numerator = (string) $this->numerator;
+ $denominator = (string) $this->denominator;
+
+ if ($denominator === '1') {
+ return $numerator;
+ }
+
+ return $this->numerator . '/' . $this->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
+ *
+ * @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);
+ }
+}
diff --git a/brick/math/src/Exception/DivisionByZeroException.php b/brick/math/src/Exception/DivisionByZeroException.php
new file mode 100644
index 000000000..a4e443176
--- /dev/null
+++ b/brick/math/src/Exception/DivisionByZeroException.php
@@ -0,0 +1,41 @@
+ 126) {
+ $char = \strtoupper(\dechex($ord));
+
+ if ($ord < 10) {
+ $char = '0' . $char;
+ }
+ } else {
+ $char = '"' . $char . '"';
+ }
+
+ return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char));
+ }
+}
diff --git a/brick/math/src/Exception/RoundingNecessaryException.php b/brick/math/src/Exception/RoundingNecessaryException.php
new file mode 100644
index 000000000..1c6100563
--- /dev/null
+++ b/brick/math/src/Exception/RoundingNecessaryException.php
@@ -0,0 +1,21 @@
+init($a, $b);
+
+ if ($aNeg && ! $bNeg) {
+ return -1;
+ }
+
+ if ($bNeg && ! $aNeg) {
+ return 1;
+ }
+
+ $aLen = \strlen($aDig);
+ $bLen = \strlen($bDig);
+
+ if ($aLen < $bLen) {
+ $result = -1;
+ } elseif ($aLen > $bLen) {
+ $result = 1;
+ } else {
+ $result = $aDig <=> $bDig;
+ }
+
+ return $aNeg ? -$result : $result;
+ }
+
+ /**
+ * 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;
+
+ /**
+ * Returns the quotient of the division of two numbers.
+ *
+ * @param string $a The dividend.
+ * @param string $b The divisor, must not be zero.
+ *
+ * @return string The quotient.
+ */
+ abstract public function divQ(string $a, string $b) : string;
+
+ /**
+ * Returns the remainder of the division of two numbers.
+ *
+ * @param string $a The dividend.
+ * @param string $b The divisor, must not be zero.
+ *
+ * @return string The remainder.
+ */
+ abstract public function divR(string $a, string $b) : string;
+
+ /**
+ * Returns the quotient and remainder of the division of two numbers.
+ *
+ * @param string $a The dividend.
+ * @param string $b The divisor, must not be zero.
+ *
+ * @return string[] An array containing the quotient and remainder.
+ */
+ abstract public function divQR(string $a, string $b) : array;
+
+ /**
+ * Exponentiates a number.
+ *
+ * @param string $a The base number.
+ * @param int $e The exponent, validated as an integer between 0 and MAX_POWER.
+ *
+ * @return string The power.
+ */
+ 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
+ {
+ return $this->divR($this->add($this->divR($a, $b), $b), $b);
+ }
+
+ /**
+ * Returns the modular multiplicative inverse of $x modulo $m.
+ *
+ * If $x has no multiplicative inverse mod m, this method must return null.
+ *
+ * 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
+ {
+ if ($m === '1') {
+ return '0';
+ }
+
+ $modVal = $x;
+
+ if ($x[0] === '-' || ($this->cmp($this->abs($x), $m) >= 0)) {
+ $modVal = $this->mod($x, $m);
+ }
+
+ $x = '0';
+ $y = '0';
+ $g = $this->gcdExtended($modVal, $m, $x, $y);
+
+ if ($g !== '1') {
+ return null;
+ }
+
+ return $this->mod($this->add($this->mod($x, $m), $m), $m);
+ }
+
+ /**
+ * Raises a number into power with modulo.
+ *
+ * @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;
+
+ /**
+ * Returns the greatest common divisor of the two numbers.
+ *
+ * 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
+ {
+ if ($a === '0') {
+ return $this->abs($b);
+ }
+
+ if ($b === '0') {
+ return $this->abs($a);
+ }
+
+ return $this->gcd($b, $this->divR($a, $b));
+ }
+
+ private function gcdExtended(string $a, string $b, string &$x, string &$y) : string
+ {
+ if ($a === '0') {
+ $x = '0';
+ $y = '1';
+
+ return $b;
+ }
+
+ $x1 = '0';
+ $y1 = '0';
+
+ $gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1);
+
+ $x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1));
+ $y = $x1;
+
+ return $gcd;
+ }
+
+ /**
+ * Returns the square root of the given number, rounded down.
+ *
+ * The result is the largest x such that x² ≤ n.
+ * The input MUST NOT be negative.
+ *
+ * @param string $n The number.
+ *
+ * @return string The square root.
+ */
+ abstract public function sqrt(string $n) : string;
+
+ /**
+ * Converts a number from an arbitrary base.
+ *
+ * This method can be overridden by the concrete implementation if the underlying library
+ * has built-in support for base conversion.
+ *
+ * @param string $number The number, positive or zero, non-empty, case-insensitively validated for the given base.
+ * @param int $base The base of the number, validated from 2 to 36.
+ *
+ * @return string The converted number, following the Calculator conventions.
+ */
+ public function fromBase(string $number, int $base) : string
+ {
+ return $this->fromArbitraryBase(\strtolower($number), self::ALPHABET, $base);
+ }
+
+ /**
+ * Converts a number to an arbitrary base.
+ *
+ * This method can be overridden by the concrete implementation if the underlying library
+ * has built-in support for base conversion.
+ *
+ * @param string $number The number to convert, following the Calculator conventions.
+ * @param int $base The base to convert to, validated from 2 to 36.
+ *
+ * @return string The converted number, lowercase.
+ */
+ public function toBase(string $number, int $base) : string
+ {
+ $negative = ($number[0] === '-');
+
+ if ($negative) {
+ $number = \substr($number, 1);
+ }
+
+ $number = $this->toArbitraryBase($number, self::ALPHABET, $base);
+
+ if ($negative) {
+ return '-' . $number;
+ }
+
+ return $number;
+ }
+
+ /**
+ * Converts a non-negative number in an arbitrary base using a custom alphabet, to base 10.
+ *
+ * @param string $number The number to convert, validated as a non-empty string,
+ * containing only chars in the given alphabet/base.
+ * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum.
+ * @param int $base The base of the number, validated from 2 to alphabet length.
+ *
+ * @return string The number in base 10, following the Calculator conventions.
+ */
+ final public function fromArbitraryBase(string $number, string $alphabet, int $base) : string
+ {
+ // remove leading "zeros"
+ $number = \ltrim($number, $alphabet[0]);
+
+ if ($number === '') {
+ return '0';
+ }
+
+ // optimize for "one"
+ if ($number === $alphabet[1]) {
+ return '1';
+ }
+
+ $result = '0';
+ $power = '1';
+
+ $base = (string) $base;
+
+ for ($i = \strlen($number) - 1; $i >= 0; $i--) {
+ $index = \strpos($alphabet, $number[$i]);
+
+ if ($index !== 0) {
+ $result = $this->add($result, ($index === 1)
+ ? $power
+ : $this->mul($power, (string) $index)
+ );
+ }
+
+ if ($i !== 0) {
+ $power = $this->mul($power, $base);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Converts a non-negative number to an arbitrary base using a custom alphabet.
+ *
+ * @param string $number The number to convert, positive or zero, following the Calculator conventions.
+ * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum.
+ * @param int $base The base to convert to, validated from 2 to alphabet length.
+ *
+ * @return string The converted number in the given alphabet.
+ */
+ final public function toArbitraryBase(string $number, string $alphabet, int $base) : string
+ {
+ if ($number === '0') {
+ return $alphabet[0];
+ }
+
+ $base = (string) $base;
+ $result = '';
+
+ while ($number !== '0') {
+ [$number, $remainder] = $this->divQR($number, $base);
+ $remainder = (int) $remainder;
+
+ $result .= $alphabet[$remainder];
+ }
+
+ return \strrev($result);
+ }
+
+ /**
+ * Performs a rounded division.
+ *
+ * Rounding is performed when the remainder of the division is not zero.
+ *
+ * @param string $a The dividend.
+ * @param string $b The divisor.
+ * @param int $roundingMode The rounding mode.
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the rounding mode is invalid.
+ * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary.
+ */
+ final public function divRound(string $a, string $b, int $roundingMode) : string
+ {
+ [$quotient, $remainder] = $this->divQR($a, $b);
+
+ $hasDiscardedFraction = ($remainder !== '0');
+ $isPositiveOrZero = ($a[0] === '-') === ($b[0] === '-');
+
+ $discardedFractionSign = function() use ($remainder, $b) : int {
+ $r = $this->abs($this->mul($remainder, '2'));
+ $b = $this->abs($b);
+
+ return $this->cmp($r, $b);
+ };
+
+ $increment = false;
+
+ switch ($roundingMode) {
+ case RoundingMode::UNNECESSARY:
+ if ($hasDiscardedFraction) {
+ throw RoundingNecessaryException::roundingNecessary();
+ }
+ break;
+
+ case RoundingMode::UP:
+ $increment = $hasDiscardedFraction;
+ break;
+
+ case RoundingMode::DOWN:
+ break;
+
+ case RoundingMode::CEILING:
+ $increment = $hasDiscardedFraction && $isPositiveOrZero;
+ break;
+
+ case RoundingMode::FLOOR:
+ $increment = $hasDiscardedFraction && ! $isPositiveOrZero;
+ break;
+
+ case RoundingMode::HALF_UP:
+ $increment = $discardedFractionSign() >= 0;
+ break;
+
+ case RoundingMode::HALF_DOWN:
+ $increment = $discardedFractionSign() > 0;
+ break;
+
+ case RoundingMode::HALF_CEILING:
+ $increment = $isPositiveOrZero ? $discardedFractionSign() >= 0 : $discardedFractionSign() > 0;
+ break;
+
+ case RoundingMode::HALF_FLOOR:
+ $increment = $isPositiveOrZero ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0;
+ break;
+
+ case RoundingMode::HALF_EVEN:
+ $lastDigit = (int) $quotient[-1];
+ $lastDigitIsEven = ($lastDigit % 2 === 0);
+ $increment = $lastDigitIsEven ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0;
+ break;
+
+ default:
+ throw new \InvalidArgumentException('Invalid rounding mode.');
+ }
+
+ if ($increment) {
+ return $this->add($quotient, $isPositiveOrZero ? '1' : '-1');
+ }
+
+ return $quotient;
+ }
+
+ /**
+ * Calculates bitwise AND of two numbers.
+ *
+ * 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
+ {
+ return $this->bitwise('and', $a, $b);
+ }
+
+ /**
+ * Calculates bitwise OR of two numbers.
+ *
+ * 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
+ {
+ return $this->bitwise('or', $a, $b);
+ }
+
+ /**
+ * Calculates bitwise XOR of two numbers.
+ *
+ * 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
+ {
+ return $this->bitwise('xor', $a, $b);
+ }
+
+ /**
+ * Performs a bitwise operation on a decimal number.
+ *
+ * @param string $operator The operator to use, must be "and", "or" or "xor".
+ * @param string $a The left operand.
+ * @param string $b The right operand.
+ *
+ * @return string
+ */
+ private function bitwise(string $operator, string $a, string $b) : string
+ {
+ [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
+
+ $aBin = $this->toBinary($aDig);
+ $bBin = $this->toBinary($bDig);
+
+ $aLen = \strlen($aBin);
+ $bLen = \strlen($bBin);
+
+ if ($aLen > $bLen) {
+ $bBin = \str_repeat("\x00", $aLen - $bLen) . $bBin;
+ } elseif ($bLen > $aLen) {
+ $aBin = \str_repeat("\x00", $bLen - $aLen) . $aBin;
+ }
+
+ if ($aNeg) {
+ $aBin = $this->twosComplement($aBin);
+ }
+ if ($bNeg) {
+ $bBin = $this->twosComplement($bBin);
+ }
+
+ switch ($operator) {
+ case 'and':
+ $value = $aBin & $bBin;
+ $negative = ($aNeg and $bNeg);
+ break;
+
+ 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
+ }
+
+ if ($negative) {
+ $value = $this->twosComplement($value);
+ }
+
+ $result = $this->toDecimal($value);
+
+ return $negative ? $this->neg($result) : $result;
+ }
+
+ /**
+ * @param string $number A positive, binary number.
+ *
+ * @return string
+ */
+ private function twosComplement(string $number) : string
+ {
+ $xor = \str_repeat("\xff", \strlen($number));
+
+ $number = $number ^ $xor;
+
+ for ($i = \strlen($number) - 1; $i >= 0; $i--) {
+ $byte = \ord($number[$i]);
+
+ if (++$byte !== 256) {
+ $number[$i] = \chr($byte);
+ break;
+ }
+
+ $number[$i] = "\x00";
+
+ if ($i === 0) {
+ $number = "\x01" . $number;
+ }
+ }
+
+ return $number;
+ }
+
+ /**
+ * 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
+ {
+ $result = '';
+
+ while ($number !== '0') {
+ [$number, $remainder] = $this->divQR($number, '256');
+ $result .= \chr((int) $remainder);
+ }
+
+ return \strrev($result);
+ }
+
+ /**
+ * 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
+ {
+ $result = '0';
+ $power = '1';
+
+ for ($i = \strlen($bytes) - 1; $i >= 0; $i--) {
+ $index = \ord($bytes[$i]);
+
+ if ($index !== 0) {
+ $result = $this->add($result, ($index === 1)
+ ? $power
+ : $this->mul($power, (string) $index)
+ );
+ }
+
+ if ($i !== 0) {
+ $power = $this->mul($power, '256');
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/brick/math/src/Internal/Calculator/BcMathCalculator.php b/brick/math/src/Internal/Calculator/BcMathCalculator.php
new file mode 100644
index 000000000..c087245bd
--- /dev/null
+++ b/brick/math/src/Internal/Calculator/BcMathCalculator.php
@@ -0,0 +1,92 @@
+maxDigits = 9;
+ break;
+
+ case 8:
+ $this->maxDigits = 18;
+ break;
+
+ default:
+ throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add(string $a, string $b) : string
+ {
+ $result = $a + $b;
+
+ if (is_int($result)) {
+ return (string) $result;
+ }
+
+ if ($a === '0') {
+ return $b;
+ }
+
+ if ($b === '0') {
+ return $a;
+ }
+
+ [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
+
+ if ($aNeg === $bNeg) {
+ $result = $this->doAdd($aDig, $bDig);
+ } else {
+ $result = $this->doSub($aDig, $bDig);
+ }
+
+ if ($aNeg) {
+ $result = $this->neg($result);
+ }
+
+ return $result;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function sub(string $a, string $b) : string
+ {
+ return $this->add($a, $this->neg($b));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mul(string $a, string $b) : string
+ {
+ $result = $a * $b;
+
+ if (is_int($result)) {
+ return (string) $result;
+ }
+
+ if ($a === '0' || $b === '0') {
+ return '0';
+ }
+
+ if ($a === '1') {
+ return $b;
+ }
+
+ if ($b === '1') {
+ return $a;
+ }
+
+ if ($a === '-1') {
+ return $this->neg($b);
+ }
+
+ if ($b === '-1') {
+ return $this->neg($a);
+ }
+
+ [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
+
+ $result = $this->doMul($aDig, $bDig);
+
+ if ($aNeg !== $bNeg) {
+ $result = $this->neg($result);
+ }
+
+ return $result;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function divQ(string $a, string $b) : string
+ {
+ return $this->divQR($a, $b)[0];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function divR(string $a, string $b): string
+ {
+ return $this->divQR($a, $b)[1];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function divQR(string $a, string $b) : array
+ {
+ if ($a === '0') {
+ return ['0', '0'];
+ }
+
+ if ($a === $b) {
+ return ['1', '0'];
+ }
+
+ if ($b === '1') {
+ return [$a, '0'];
+ }
+
+ if ($b === '-1') {
+ return [$this->neg($a), '0'];
+ }
+
+ $na = $a * 1; // cast to number
+
+ if (is_int($na)) {
+ $nb = $b * 1;
+
+ 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.
+ $r = $na % $nb;
+ $q = ($na - $r) / $nb;
+
+ assert(is_int($q));
+
+ return [
+ (string) $q,
+ (string) $r
+ ];
+ }
+ }
+
+ [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
+
+ [$q, $r] = $this->doDiv($aDig, $bDig);
+
+ if ($aNeg !== $bNeg) {
+ $q = $this->neg($q);
+ }
+
+ if ($aNeg) {
+ $r = $this->neg($r);
+ }
+
+ return [$q, $r];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pow(string $a, int $e) : string
+ {
+ if ($e === 0) {
+ return '1';
+ }
+
+ if ($e === 1) {
+ return $a;
+ }
+
+ $odd = $e % 2;
+ $e -= $odd;
+
+ $aa = $this->mul($a, $a);
+ $result = $this->pow($aa, $e / 2);
+
+ if ($odd === 1) {
+ $result = $this->mul($result, $a);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Algorithm from: https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/
+ *
+ * {@inheritdoc}
+ */
+ 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)
+ if ($base === '0' && $exp === '0' && $mod === '1') {
+ return '0';
+ }
+
+ // special case: the algorithm below fails with power 0 mod 1 (returns 1 instead of 0)
+ if ($exp === '0' && $mod === '1') {
+ return '0';
+ }
+
+ $x = $base;
+
+ $res = '1';
+
+ // numbers are positive, so we can use remainder instead of modulo
+ $x = $this->divR($x, $mod);
+
+ while ($exp !== '0') {
+ if (in_array($exp[-1], ['1', '3', '5', '7', '9'])) { // odd
+ $res = $this->divR($this->mul($res, $x), $mod);
+ }
+
+ $exp = $this->divQ($exp, '2');
+ $x = $this->divR($this->mul($x, $x), $mod);
+ }
+
+ return $res;
+ }
+
+ /**
+ * Adapted from https://cp-algorithms.com/num_methods/roots_newton.html
+ *
+ * {@inheritDoc}
+ */
+ public function sqrt(string $n) : string
+ {
+ if ($n === '0') {
+ return '0';
+ }
+
+ // initial approximation
+ $x = \str_repeat('9', \intdiv(\strlen($n), 2) ?: 1);
+
+ $decreased = false;
+
+ for (;;) {
+ $nx = $this->divQ($this->add($x, $this->divQ($n, $x)), '2');
+
+ if ($x === $nx || $this->cmp($nx, $x) > 0 && $decreased) {
+ break;
+ }
+
+ $decreased = $this->cmp($nx, $x) < 0;
+ $x = $nx;
+ }
+
+ return $x;
+ }
+
+ /**
+ * 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
+ {
+ [$a, $b, $length] = $this->pad($a, $b);
+
+ $carry = 0;
+ $result = '';
+
+ for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) {
+ $blockLength = $this->maxDigits;
+
+ if ($i < 0) {
+ $blockLength += $i;
+ $i = 0;
+ }
+
+ $blockA = \substr($a, $i, $blockLength);
+ $blockB = \substr($b, $i, $blockLength);
+
+ $sum = (string) ($blockA + $blockB + $carry);
+ $sumLength = \strlen($sum);
+
+ if ($sumLength > $blockLength) {
+ $sum = \substr($sum, 1);
+ $carry = 1;
+ } else {
+ if ($sumLength < $blockLength) {
+ $sum = \str_repeat('0', $blockLength - $sumLength) . $sum;
+ }
+ $carry = 0;
+ }
+
+ $result = $sum . $result;
+
+ if ($i === 0) {
+ break;
+ }
+ }
+
+ if ($carry === 1) {
+ $result = '1' . $result;
+ }
+
+ return $result;
+ }
+
+ /**
+ * 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
+ {
+ if ($a === $b) {
+ return '0';
+ }
+
+ // Ensure that we always subtract to a positive result: biggest minus smallest.
+ $cmp = $this->doCmp($a, $b);
+
+ $invert = ($cmp === -1);
+
+ if ($invert) {
+ $c = $a;
+ $a = $b;
+ $b = $c;
+ }
+
+ [$a, $b, $length] = $this->pad($a, $b);
+
+ $carry = 0;
+ $result = '';
+
+ $complement = 10 ** $this->maxDigits;
+
+ for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) {
+ $blockLength = $this->maxDigits;
+
+ if ($i < 0) {
+ $blockLength += $i;
+ $i = 0;
+ }
+
+ $blockA = \substr($a, $i, $blockLength);
+ $blockB = \substr($b, $i, $blockLength);
+
+ $sum = $blockA - $blockB - $carry;
+
+ if ($sum < 0) {
+ $sum += $complement;
+ $carry = 1;
+ } else {
+ $carry = 0;
+ }
+
+ $sum = (string) $sum;
+ $sumLength = \strlen($sum);
+
+ if ($sumLength < $blockLength) {
+ $sum = \str_repeat('0', $blockLength - $sumLength) . $sum;
+ }
+
+ $result = $sum . $result;
+
+ if ($i === 0) {
+ break;
+ }
+ }
+
+ // Carry cannot be 1 when the loop ends, as a > b
+ assert($carry === 0);
+
+ $result = \ltrim($result, '0');
+
+ if ($invert) {
+ $result = $this->neg($result);
+ }
+
+ return $result;
+ }
+
+ /**
+ * 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
+ {
+ $x = \strlen($a);
+ $y = \strlen($b);
+
+ $maxDigits = \intdiv($this->maxDigits, 2);
+ $complement = 10 ** $maxDigits;
+
+ $result = '0';
+
+ for ($i = $x - $maxDigits;; $i -= $maxDigits) {
+ $blockALength = $maxDigits;
+
+ if ($i < 0) {
+ $blockALength += $i;
+ $i = 0;
+ }
+
+ $blockA = (int) \substr($a, $i, $blockALength);
+
+ $line = '';
+ $carry = 0;
+
+ for ($j = $y - $maxDigits;; $j -= $maxDigits) {
+ $blockBLength = $maxDigits;
+
+ if ($j < 0) {
+ $blockBLength += $j;
+ $j = 0;
+ }
+
+ $blockB = (int) \substr($b, $j, $blockBLength);
+
+ $mul = $blockA * $blockB + $carry;
+ $value = $mul % $complement;
+ $carry = ($mul - $value) / $complement;
+
+ $value = (string) $value;
+ $value = \str_pad($value, $maxDigits, '0', STR_PAD_LEFT);
+
+ $line = $value . $line;
+
+ if ($j === 0) {
+ break;
+ }
+ }
+
+ if ($carry !== 0) {
+ $line = $carry . $line;
+ }
+
+ $line = \ltrim($line, '0');
+
+ if ($line !== '') {
+ $line .= \str_repeat('0', $x - $blockALength - $i);
+ $result = $this->add($result, $line);
+ }
+
+ if ($i === 0) {
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * 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
+ {
+ $cmp = $this->doCmp($a, $b);
+
+ if ($cmp === -1) {
+ return ['0', $a];
+ }
+
+ $x = \strlen($a);
+ $y = \strlen($b);
+
+ // we now know that a >= b && x >= y
+
+ $q = '0'; // quotient
+ $r = $a; // remainder
+ $z = $y; // focus length, always $y or $y+1
+
+ for (;;) {
+ $focus = \substr($a, 0, $z);
+
+ $cmp = $this->doCmp($focus, $b);
+
+ if ($cmp === -1) {
+ if ($z === $x) { // remainder < dividend
+ break;
+ }
+
+ $z++;
+ }
+
+ $zeros = \str_repeat('0', $x - $z);
+
+ $q = $this->add($q, '1' . $zeros);
+ $a = $this->sub($a, $b . $zeros);
+
+ $r = $a;
+
+ if ($r === '0') { // remainder == 0
+ break;
+ }
+
+ $x = \strlen($a);
+
+ if ($x < $y) { // remainder < dividend
+ break;
+ }
+
+ $z = $y;
+ }
+
+ return [$q, $r];
+ }
+
+ /**
+ * Compares two non-signed large numbers.
+ *
+ * @param string $a The first operand.
+ * @param string $b The second operand.
+ *
+ * @return int [-1, 0, 1]
+ */
+ private function doCmp(string $a, string $b) : int
+ {
+ $x = \strlen($a);
+ $y = \strlen($b);
+
+ $cmp = $x <=> $y;
+
+ if ($cmp !== 0) {
+ return $cmp;
+ }
+
+ return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1]
+ }
+
+ /**
+ * Pads the left of one of the given numbers with zeros if necessary to make both numbers the same length.
+ *
+ * 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{0: string, 1: string, 2: int}
+ */
+ private function pad(string $a, string $b) : array
+ {
+ $x = \strlen($a);
+ $y = \strlen($b);
+
+ if ($x > $y) {
+ $b = \str_repeat('0', $x - $y) . $b;
+
+ return [$a, $b, $x];
+ }
+
+ if ($x < $y) {
+ $a = \str_repeat('0', $y - $x) . $a;
+
+ return [$a, $b, $y];
+ }
+
+ return [$a, $b, $x];
+ }
+}
diff --git a/brick/math/src/RoundingMode.php b/brick/math/src/RoundingMode.php
new file mode 100644
index 000000000..06936d8db
--- /dev/null
+++ b/brick/math/src/RoundingMode.php
@@ -0,0 +1,107 @@
+= 0.5; otherwise, behaves as for DOWN.
+ * Note that this is the rounding mode commonly taught at school.
+ */
+ public const HALF_UP = 5;
+
+ /**
+ * 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;
+
+ /**
+ * 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;
+
+ /**
+ * 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;
+
+ /**
+ * Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor.
+ *
+ * Behaves as for HALF_UP if the digit to the left of the discarded fraction is odd;
+ * behaves as for HALF_DOWN if it's even.
+ *
+ * Note that this is the rounding mode that statistically minimizes
+ * 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;
+}
diff --git a/composer/ClassLoader.php b/composer/ClassLoader.php
index 6d0c3f2d0..0cd6055d1 100644
--- a/composer/ClassLoader.php
+++ b/composer/ClassLoader.php
@@ -42,30 +42,75 @@
*/
class ClassLoader
{
+ /** @var ?string */
private $vendorDir;
// PSR-4
+ /**
+ * @var array[]
+ * @psalm-var array>
+ */
private $prefixLengthsPsr4 = array();
+ /**
+ * @var array[]
+ * @psalm-var array>
+ */
private $prefixDirsPsr4 = array();
+ /**
+ * @var array[]
+ * @psalm-var array
+ */
private $fallbackDirsPsr4 = array();
// PSR-0
+ /**
+ * @var array[]
+ * @psalm-var array>
+ */
private $prefixesPsr0 = array();
+ /**
+ * @var array[]
+ * @psalm-var array
+ */
private $fallbackDirsPsr0 = array();
+ /** @var bool */
private $useIncludePath = false;
+
+ /**
+ * @var string[]
+ * @psalm-var array
+ */
private $classMap = array();
+
+ /** @var bool */
private $classMapAuthoritative = false;
+
+ /**
+ * @var bool[]
+ * @psalm-var array
+ */
private $missingClasses = array();
+
+ /** @var ?string */
private $apcuPrefix;
+ /**
+ * @var self[]
+ */
private static $registeredLoaders = array();
+ /**
+ * @param ?string $vendorDir
+ */
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
+ /**
+ * @return string[]
+ */
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
@@ -75,28 +120,47 @@ public function getPrefixes()
return array();
}
+ /**
+ * @return array[]
+ * @psalm-return array>
+ */
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
+ /**
+ * @return array[]
+ * @psalm-return array
+ */
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
+ /**
+ * @return array[]
+ * @psalm-return array
+ */
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
+ /**
+ * @return string[] Array of classname => path
+ * @psalm-var array
+ */
public function getClassMap()
{
return $this->classMap;
}
/**
- * @param array $classMap Class to filename map
+ * @param string[] $classMap Class to filename map
+ * @psalm-param array $classMap
+ *
+ * @return void
*/
public function addClassMap(array $classMap)
{
@@ -111,9 +175,11 @@ public function addClassMap(array $classMap)
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
- * @param string $prefix The prefix
- * @param array|string $paths The PSR-0 root directories
- * @param bool $prepend Whether to prepend the directories
+ * @param string $prefix The prefix
+ * @param string[]|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @return void
*/
public function add($prefix, $paths, $prepend = false)
{
@@ -156,11 +222,13 @@ public function add($prefix, $paths, $prepend = false)
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
- * @param string $prefix The prefix/namespace, with trailing '\\'
- * @param array|string $paths The PSR-4 base directories
- * @param bool $prepend Whether to prepend the directories
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param string[]|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
+ *
+ * @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
@@ -204,8 +272,10 @@ public function addPsr4($prefix, $paths, $prepend = false)
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
- * @param string $prefix The prefix
- * @param array|string $paths The PSR-0 base directories
+ * @param string $prefix The prefix
+ * @param string[]|string $paths The PSR-0 base directories
+ *
+ * @return void
*/
public function set($prefix, $paths)
{
@@ -220,10 +290,12 @@ public function set($prefix, $paths)
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
- * @param string $prefix The prefix/namespace, with trailing '\\'
- * @param array|string $paths The PSR-4 base directories
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
+ *
+ * @return void
*/
public function setPsr4($prefix, $paths)
{
@@ -243,6 +315,8 @@ public function setPsr4($prefix, $paths)
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
+ *
+ * @return void
*/
public function setUseIncludePath($useIncludePath)
{
@@ -265,6 +339,8 @@ public function getUseIncludePath()
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
+ *
+ * @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
@@ -285,6 +361,8 @@ public function isClassMapAuthoritative()
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
+ *
+ * @return void
*/
public function setApcuPrefix($apcuPrefix)
{
@@ -305,6 +383,8 @@ public function getApcuPrefix()
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
+ *
+ * @return void
*/
public function register($prepend = false)
{
@@ -324,6 +404,8 @@ public function register($prepend = false)
/**
* Unregisters this instance as an autoloader.
+ *
+ * @return void
*/
public function unregister()
{
@@ -403,6 +485,11 @@ public static function getRegisteredLoaders()
return self::$registeredLoaders;
}
+ /**
+ * @param string $class
+ * @param string $ext
+ * @return string|false
+ */
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
@@ -474,6 +561,10 @@ private function findFileWithExtension($class, $ext)
* Scope isolated include.
*
* Prevents access to $this/self from included files.
+ *
+ * @param string $file
+ * @return void
+ * @private
*/
function includeFile($file)
{
diff --git a/composer/InstalledVersions.php b/composer/InstalledVersions.php
index b3a4e1611..7c5502ca4 100644
--- a/composer/InstalledVersions.php
+++ b/composer/InstalledVersions.php
@@ -20,7 +20,7 @@
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
- * To require it's presence, you can require `composer-runtime-api ^2.0`
+ * To require its presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions
{
@@ -228,7 +228,7 @@ public static function getInstallPath($packageName)
/**
* @return array
- * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
+ * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
*/
public static function getRootPackage()
{
@@ -242,7 +242,7 @@ public static function getRootPackage()
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
- * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array}
+ * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}
*/
public static function getRawData()
{
@@ -265,7 +265,7 @@ public static function getRawData()
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
- * @psalm-return list}>
+ * @psalm-return list}>
*/
public static function getAllRawData()
{
@@ -288,7 +288,7 @@ public static function getAllRawData()
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
- * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array} $data
+ * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data
*/
public static function reload($data)
{
@@ -298,7 +298,7 @@ public static function reload($data)
/**
* @return array[]
- * @psalm-return list}>
+ * @psalm-return list}>
*/
private static function getInstalled()
{
diff --git a/composer/autoload_classmap.php b/composer/autoload_classmap.php
index 3cb027f0b..3564cb84c 100644
--- a/composer/autoload_classmap.php
+++ b/composer/autoload_classmap.php
@@ -668,6 +668,21 @@
'Aws\\signer\\Exception\\signerException' => $vendorDir . '/aws/aws-sdk-php/src/signer/Exception/signerException.php',
'Aws\\signer\\signerClient' => $vendorDir . '/aws/aws-sdk-php/src/signer/signerClient.php',
'Base64Url\\Base64Url' => $vendorDir . '/spomky-labs/base64url/src/Base64Url.php',
+ 'Brick\\Math\\BigDecimal' => $vendorDir . '/brick/math/src/BigDecimal.php',
+ 'Brick\\Math\\BigInteger' => $vendorDir . '/brick/math/src/BigInteger.php',
+ 'Brick\\Math\\BigNumber' => $vendorDir . '/brick/math/src/BigNumber.php',
+ 'Brick\\Math\\BigRational' => $vendorDir . '/brick/math/src/BigRational.php',
+ 'Brick\\Math\\Exception\\DivisionByZeroException' => $vendorDir . '/brick/math/src/Exception/DivisionByZeroException.php',
+ 'Brick\\Math\\Exception\\IntegerOverflowException' => $vendorDir . '/brick/math/src/Exception/IntegerOverflowException.php',
+ 'Brick\\Math\\Exception\\MathException' => $vendorDir . '/brick/math/src/Exception/MathException.php',
+ 'Brick\\Math\\Exception\\NegativeNumberException' => $vendorDir . '/brick/math/src/Exception/NegativeNumberException.php',
+ 'Brick\\Math\\Exception\\NumberFormatException' => $vendorDir . '/brick/math/src/Exception/NumberFormatException.php',
+ 'Brick\\Math\\Exception\\RoundingNecessaryException' => $vendorDir . '/brick/math/src/Exception/RoundingNecessaryException.php',
+ 'Brick\\Math\\Internal\\Calculator' => $vendorDir . '/brick/math/src/Internal/Calculator.php',
+ 'Brick\\Math\\Internal\\Calculator\\BcMathCalculator' => $vendorDir . '/brick/math/src/Internal/Calculator/BcMathCalculator.php',
+ 'Brick\\Math\\Internal\\Calculator\\GmpCalculator' => $vendorDir . '/brick/math/src/Internal/Calculator/GmpCalculator.php',
+ 'Brick\\Math\\Internal\\Calculator\\NativeCalculator' => $vendorDir . '/brick/math/src/Internal/Calculator/NativeCalculator.php',
+ 'Brick\\Math\\RoundingMode' => $vendorDir . '/brick/math/src/RoundingMode.php',
'CBOR\\AbstractCBORObject' => $vendorDir . '/spomky-labs/cbor-php/src/AbstractCBORObject.php',
'CBOR\\ByteStringObject' => $vendorDir . '/spomky-labs/cbor-php/src/ByteStringObject.php',
'CBOR\\ByteStringWithChunkObject' => $vendorDir . '/spomky-labs/cbor-php/src/ByteStringWithChunkObject.php',
@@ -2460,6 +2475,97 @@
'Sabre\\Xml\\Writer' => $vendorDir . '/sabre/xml/lib/Writer.php',
'Sabre\\Xml\\XmlDeserializable' => $vendorDir . '/sabre/xml/lib/XmlDeserializable.php',
'Sabre\\Xml\\XmlSerializable' => $vendorDir . '/sabre/xml/lib/XmlSerializable.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\\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\\IngresiiException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/IngresiiException.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\\MsqlException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MsqlException.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/generated/Exceptions/MysqliException.php',
+ 'Safe\\Exceptions\\MysqlndMsException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MysqlndMsException.php',
+ 'Safe\\Exceptions\\MysqlndQcException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/MysqlndQcException.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/generated/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\\PdfException' => $vendorDir . '/thecodingmachine/safe/generated/Exceptions/PdfException.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/generated/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',
'ScssPhp\\ScssPhp\\Base\\Range' => $vendorDir . '/scssphp/scssphp/src/Base/Range.php',
'ScssPhp\\ScssPhp\\Block' => $vendorDir . '/scssphp/scssphp/src/Block.php',
'ScssPhp\\ScssPhp\\Cache' => $vendorDir . '/scssphp/scssphp/src/Cache.php',
@@ -2806,6 +2912,7 @@
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'Webauthn\\AttestationStatement\\AndroidKeyAttestationStatementSupport' => $vendorDir . '/web-auth/webauthn-lib/src/AttestationStatement/AndroidKeyAttestationStatementSupport.php',
'Webauthn\\AttestationStatement\\AndroidSafetyNetAttestationStatementSupport' => $vendorDir . '/web-auth/webauthn-lib/src/AttestationStatement/AndroidSafetyNetAttestationStatementSupport.php',
+ 'Webauthn\\AttestationStatement\\AppleAttestationStatementSupport' => $vendorDir . '/web-auth/webauthn-lib/src/AttestationStatement/AppleAttestationStatementSupport.php',
'Webauthn\\AttestationStatement\\AttestationObject' => $vendorDir . '/web-auth/webauthn-lib/src/AttestationStatement/AttestationObject.php',
'Webauthn\\AttestationStatement\\AttestationObjectLoader' => $vendorDir . '/web-auth/webauthn-lib/src/AttestationStatement/AttestationObjectLoader.php',
'Webauthn\\AttestationStatement\\AttestationStatement' => $vendorDir . '/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatement.php',
@@ -2830,6 +2937,8 @@
'Webauthn\\AuthenticatorData' => $vendorDir . '/web-auth/webauthn-lib/src/AuthenticatorData.php',
'Webauthn\\AuthenticatorResponse' => $vendorDir . '/web-auth/webauthn-lib/src/AuthenticatorResponse.php',
'Webauthn\\AuthenticatorSelectionCriteria' => $vendorDir . '/web-auth/webauthn-lib/src/AuthenticatorSelectionCriteria.php',
+ 'Webauthn\\CertificateChainChecker\\CertificateChainChecker' => $vendorDir . '/web-auth/webauthn-lib/src/CertificateChainChecker/CertificateChainChecker.php',
+ 'Webauthn\\CertificateChainChecker\\OpenSSLCertificateChainChecker' => $vendorDir . '/web-auth/webauthn-lib/src/CertificateChainChecker/OpenSSLCertificateChainChecker.php',
'Webauthn\\CertificateToolbox' => $vendorDir . '/web-auth/webauthn-lib/src/CertificateToolbox.php',
'Webauthn\\CollectedClientData' => $vendorDir . '/web-auth/webauthn-lib/src/CollectedClientData.php',
'Webauthn\\Counter\\CounterChecker' => $vendorDir . '/web-auth/webauthn-lib/src/Counter/CounterChecker.php',
diff --git a/composer/autoload_files.php b/composer/autoload_files.php
index c726eee3c..2bb4e2619 100644
--- a/composer/autoload_files.php
+++ b/composer/autoload_files.php
@@ -29,6 +29,95 @@
'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
+ '51fcf4e06c07cc00c920b44bcd900e7a' => $vendorDir . '/thecodingmachine/safe/deprecated/apc.php',
+ '47f619d9197b36cf5ab70738d7743fe2' => $vendorDir . '/thecodingmachine/safe/deprecated/libevent.php',
+ 'ea6bb8a12ef9b68f6ada99058e530760' => $vendorDir . '/thecodingmachine/safe/deprecated/mssql.php',
+ '9a29089eb3ce41a446744c68a00f118c' => $vendorDir . '/thecodingmachine/safe/deprecated/stats.php',
+ '72243e5536b63e298acb6476f01f1aff' => $vendorDir . '/thecodingmachine/safe/lib/special_cases.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',
+ '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',
+ '0c577fe603b029d4b65c84376b15dbd5' => $vendorDir . '/thecodingmachine/safe/generated/ingres-ii.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',
+ 'c112440003b56e243b192c11fa9d836e' => $vendorDir . '/thecodingmachine/safe/generated/msql.php',
+ '7cefd81607cd21b8b3a15656eb6465f5' => $vendorDir . '/thecodingmachine/safe/generated/mysql.php',
+ 'aaf438b080089c6d0686679cd34aa72e' => $vendorDir . '/thecodingmachine/safe/generated/mysqli.php',
+ 'df0ef890e9afbf95f3924feb1c7a89f3' => $vendorDir . '/thecodingmachine/safe/generated/mysqlndMs.php',
+ 'db595fee5972867e45c5327010d78735' => $vendorDir . '/thecodingmachine/safe/generated/mysqlndQc.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',
+ '1212c201fe43c7492a085b2c71505e0f' => $vendorDir . '/thecodingmachine/safe/generated/password.php',
+ '002ebcb842e2c0d5b7f67fe64cc93158' => $vendorDir . '/thecodingmachine/safe/generated/pcntl.php',
+ '86df38612982dade72c7085ce7eca81f' => $vendorDir . '/thecodingmachine/safe/generated/pcre.php',
+ '1cacc3e65f82a473fbd5507c7ce4385d' => $vendorDir . '/thecodingmachine/safe/generated/pdf.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',
+ '01352920b0151f17e671266e44b52536' => $vendorDir . '/thecodingmachine/safe/generated/simplexml.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',
'8a9dc1de0ca7e01f3e08231539562f61' => $vendorDir . '/aws/aws-sdk-php/src/functions.php',
'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
'2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
diff --git a/composer/autoload_psr4.php b/composer/autoload_psr4.php
index b0f38a655..22302727f 100644
--- a/composer/autoload_psr4.php
+++ b/composer/autoload_psr4.php
@@ -33,6 +33,7 @@
'Stecman\\Component\\Symfony\\Console\\BashCompletion\\' => array($vendorDir . '/stecman/symfony-console-completion/src'),
'SearchDAV\\' => array($vendorDir . '/icewind/searchdav/src'),
'ScssPhp\\ScssPhp\\' => array($vendorDir . '/scssphp/scssphp/src'),
+ 'Safe\\' => array($vendorDir . '/thecodingmachine/safe/lib', $vendorDir . '/thecodingmachine/safe/deprecated', $vendorDir . '/thecodingmachine/safe/generated'),
'Sabre\\Xml\\' => array($vendorDir . '/sabre/xml/lib'),
'Sabre\\VObject\\' => array($vendorDir . '/sabre/vobject/lib'),
'Sabre\\Uri\\' => array($vendorDir . '/sabre/uri/lib'),
@@ -80,6 +81,7 @@
'Doctrine\\Common\\' => array($vendorDir . '/doctrine/common/lib/Doctrine/Common', $vendorDir . '/doctrine/event-manager/lib/Doctrine/Common', $vendorDir . '/doctrine/persistence/lib/Doctrine/Common', $vendorDir . '/doctrine/reflection/lib/Doctrine/Common'),
'Cose\\' => array($vendorDir . '/web-auth/cose-lib/src'),
'CBOR\\' => array($vendorDir . '/spomky-labs/cbor-php/src'),
+ 'Brick\\Math\\' => array($vendorDir . '/brick/math/src'),
'Base64Url\\' => array($vendorDir . '/spomky-labs/base64url/src'),
'Aws\\' => array($vendorDir . '/aws/aws-sdk-php/src'),
'Assert\\' => array($vendorDir . '/beberlei/assert/lib/Assert'),
diff --git a/composer/autoload_static.php b/composer/autoload_static.php
index 290500631..bae92848a 100644
--- a/composer/autoload_static.php
+++ b/composer/autoload_static.php
@@ -30,6 +30,95 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652
'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
+ '51fcf4e06c07cc00c920b44bcd900e7a' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/apc.php',
+ '47f619d9197b36cf5ab70738d7743fe2' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/libevent.php',
+ 'ea6bb8a12ef9b68f6ada99058e530760' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/mssql.php',
+ '9a29089eb3ce41a446744c68a00f118c' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/stats.php',
+ '72243e5536b63e298acb6476f01f1aff' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/special_cases.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',
+ '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',
+ '0c577fe603b029d4b65c84376b15dbd5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ingres-ii.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',
+ 'c112440003b56e243b192c11fa9d836e' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/msql.php',
+ '7cefd81607cd21b8b3a15656eb6465f5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysql.php',
+ 'aaf438b080089c6d0686679cd34aa72e' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysqli.php',
+ 'df0ef890e9afbf95f3924feb1c7a89f3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysqlndMs.php',
+ 'db595fee5972867e45c5327010d78735' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysqlndQc.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',
+ '1212c201fe43c7492a085b2c71505e0f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/password.php',
+ '002ebcb842e2c0d5b7f67fe64cc93158' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pcntl.php',
+ '86df38612982dade72c7085ce7eca81f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pcre.php',
+ '1cacc3e65f82a473fbd5507c7ce4385d' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pdf.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',
+ '01352920b0151f17e671266e44b52536' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/simplexml.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',
'8a9dc1de0ca7e01f3e08231539562f61' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/functions.php',
'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
'2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php',
@@ -80,6 +169,7 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652
'Stecman\\Component\\Symfony\\Console\\BashCompletion\\' => 49,
'SearchDAV\\' => 10,
'ScssPhp\\ScssPhp\\' => 16,
+ 'Safe\\' => 5,
'Sabre\\Xml\\' => 10,
'Sabre\\VObject\\' => 14,
'Sabre\\Uri\\' => 10,
@@ -172,6 +262,7 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652
),
'B' =>
array (
+ 'Brick\\Math\\' => 11,
'Base64Url\\' => 10,
),
'A' =>
@@ -290,6 +381,12 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652
array (
0 => __DIR__ . '/..' . '/scssphp/scssphp/src',
),
+ 'Safe\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/thecodingmachine/safe/lib',
+ 1 => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated',
+ 2 => __DIR__ . '/..' . '/thecodingmachine/safe/generated',
+ ),
'Sabre\\Xml\\' =>
array (
0 => __DIR__ . '/..' . '/sabre/xml/lib',
@@ -484,6 +581,10 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652
array (
0 => __DIR__ . '/..' . '/spomky-labs/cbor-php/src',
),
+ 'Brick\\Math\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/brick/math/src',
+ ),
'Base64Url\\' =>
array (
0 => __DIR__ . '/..' . '/spomky-labs/base64url/src',
@@ -1196,6 +1297,21 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652
'Aws\\signer\\Exception\\signerException' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/signer/Exception/signerException.php',
'Aws\\signer\\signerClient' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/signer/signerClient.php',
'Base64Url\\Base64Url' => __DIR__ . '/..' . '/spomky-labs/base64url/src/Base64Url.php',
+ 'Brick\\Math\\BigDecimal' => __DIR__ . '/..' . '/brick/math/src/BigDecimal.php',
+ 'Brick\\Math\\BigInteger' => __DIR__ . '/..' . '/brick/math/src/BigInteger.php',
+ 'Brick\\Math\\BigNumber' => __DIR__ . '/..' . '/brick/math/src/BigNumber.php',
+ 'Brick\\Math\\BigRational' => __DIR__ . '/..' . '/brick/math/src/BigRational.php',
+ 'Brick\\Math\\Exception\\DivisionByZeroException' => __DIR__ . '/..' . '/brick/math/src/Exception/DivisionByZeroException.php',
+ 'Brick\\Math\\Exception\\IntegerOverflowException' => __DIR__ . '/..' . '/brick/math/src/Exception/IntegerOverflowException.php',
+ 'Brick\\Math\\Exception\\MathException' => __DIR__ . '/..' . '/brick/math/src/Exception/MathException.php',
+ 'Brick\\Math\\Exception\\NegativeNumberException' => __DIR__ . '/..' . '/brick/math/src/Exception/NegativeNumberException.php',
+ 'Brick\\Math\\Exception\\NumberFormatException' => __DIR__ . '/..' . '/brick/math/src/Exception/NumberFormatException.php',
+ 'Brick\\Math\\Exception\\RoundingNecessaryException' => __DIR__ . '/..' . '/brick/math/src/Exception/RoundingNecessaryException.php',
+ 'Brick\\Math\\Internal\\Calculator' => __DIR__ . '/..' . '/brick/math/src/Internal/Calculator.php',
+ 'Brick\\Math\\Internal\\Calculator\\BcMathCalculator' => __DIR__ . '/..' . '/brick/math/src/Internal/Calculator/BcMathCalculator.php',
+ 'Brick\\Math\\Internal\\Calculator\\GmpCalculator' => __DIR__ . '/..' . '/brick/math/src/Internal/Calculator/GmpCalculator.php',
+ 'Brick\\Math\\Internal\\Calculator\\NativeCalculator' => __DIR__ . '/..' . '/brick/math/src/Internal/Calculator/NativeCalculator.php',
+ 'Brick\\Math\\RoundingMode' => __DIR__ . '/..' . '/brick/math/src/RoundingMode.php',
'CBOR\\AbstractCBORObject' => __DIR__ . '/..' . '/spomky-labs/cbor-php/src/AbstractCBORObject.php',
'CBOR\\ByteStringObject' => __DIR__ . '/..' . '/spomky-labs/cbor-php/src/ByteStringObject.php',
'CBOR\\ByteStringWithChunkObject' => __DIR__ . '/..' . '/spomky-labs/cbor-php/src/ByteStringWithChunkObject.php',
@@ -2988,6 +3104,97 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652
'Sabre\\Xml\\Writer' => __DIR__ . '/..' . '/sabre/xml/lib/Writer.php',
'Sabre\\Xml\\XmlDeserializable' => __DIR__ . '/..' . '/sabre/xml/lib/XmlDeserializable.php',
'Sabre\\Xml\\XmlSerializable' => __DIR__ . '/..' . '/sabre/xml/lib/XmlSerializable.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\\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\\IngresiiException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/IngresiiException.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\\MsqlException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MsqlException.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/generated/Exceptions/MysqliException.php',
+ 'Safe\\Exceptions\\MysqlndMsException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MysqlndMsException.php',
+ 'Safe\\Exceptions\\MysqlndQcException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/MysqlndQcException.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/generated/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\\PdfException' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/Exceptions/PdfException.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/generated/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',
'ScssPhp\\ScssPhp\\Base\\Range' => __DIR__ . '/..' . '/scssphp/scssphp/src/Base/Range.php',
'ScssPhp\\ScssPhp\\Block' => __DIR__ . '/..' . '/scssphp/scssphp/src/Block.php',
'ScssPhp\\ScssPhp\\Cache' => __DIR__ . '/..' . '/scssphp/scssphp/src/Cache.php',
@@ -3334,6 +3541,7 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'Webauthn\\AttestationStatement\\AndroidKeyAttestationStatementSupport' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/AttestationStatement/AndroidKeyAttestationStatementSupport.php',
'Webauthn\\AttestationStatement\\AndroidSafetyNetAttestationStatementSupport' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/AttestationStatement/AndroidSafetyNetAttestationStatementSupport.php',
+ 'Webauthn\\AttestationStatement\\AppleAttestationStatementSupport' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/AttestationStatement/AppleAttestationStatementSupport.php',
'Webauthn\\AttestationStatement\\AttestationObject' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/AttestationStatement/AttestationObject.php',
'Webauthn\\AttestationStatement\\AttestationObjectLoader' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/AttestationStatement/AttestationObjectLoader.php',
'Webauthn\\AttestationStatement\\AttestationStatement' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatement.php',
@@ -3358,6 +3566,8 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652
'Webauthn\\AuthenticatorData' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/AuthenticatorData.php',
'Webauthn\\AuthenticatorResponse' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/AuthenticatorResponse.php',
'Webauthn\\AuthenticatorSelectionCriteria' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/AuthenticatorSelectionCriteria.php',
+ 'Webauthn\\CertificateChainChecker\\CertificateChainChecker' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/CertificateChainChecker/CertificateChainChecker.php',
+ 'Webauthn\\CertificateChainChecker\\OpenSSLCertificateChainChecker' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/CertificateChainChecker/OpenSSLCertificateChainChecker.php',
'Webauthn\\CertificateToolbox' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/CertificateToolbox.php',
'Webauthn\\CollectedClientData' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/CollectedClientData.php',
'Webauthn\\Counter\\CounterChecker' => __DIR__ . '/..' . '/web-auth/webauthn-lib/src/Counter/CounterChecker.php',
diff --git a/composer/installed.php b/composer/installed.php
index ec5f2dde8..ff4894135 100644
--- a/composer/installed.php
+++ b/composer/installed.php
@@ -5,7 +5,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
- 'reference' => 'fe8eec01832697f8d94c0c359639f126a11a4da7',
+ 'reference' => '1ee082805468bf54a6ecd77c594f612f9c529316',
'name' => 'nextcloud/3rdparty',
'dev' => false,
),
@@ -322,7 +322,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
- 'reference' => 'fe8eec01832697f8d94c0c359639f126a11a4da7',
+ 'reference' => '1ee082805468bf54a6ecd77c594f612f9c529316',
'dev_requirement' => false,
),
'nextcloud/lognormalizer' => array(
diff --git a/thecodingmachine/safe/LICENSE b/thecodingmachine/safe/LICENSE
new file mode 100644
index 000000000..4188a9bbd
--- /dev/null
+++ b/thecodingmachine/safe/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 TheCodingMachine
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/thecodingmachine/safe/README.md b/thecodingmachine/safe/README.md
new file mode 100644
index 000000000..3c2ee624f
--- /dev/null
+++ b/thecodingmachine/safe/README.md
@@ -0,0 +1,178 @@
+[](https://packagist.org/packages/thecodingmachine/safe)
+[](https://packagist.org/packages/thecodingmachine/safe)
+[](https://packagist.org/packages/thecodingmachine/safe)
+[](https://packagist.org/packages/thecodingmachine/safe)
+[](https://travis-ci.org/thecodingmachine/safe)
+[](https://github.com/thecodingmachine/safe/actions)
+[](https://codecov.io/gh/thecodingmachine/safe)
+
+Safe PHP
+========
+
+**Work in progress**
+
+A set of core PHP functions rewritten to throw exceptions instead of returning `false` when an error is encountered.
+
+## The problem
+
+Most PHP core functions were written before exception handling was added to the language. Therefore, most PHP functions
+do not throw exceptions. Instead, they return `false` in case of error.
+
+But most of us are too lazy to check explicitly for every single return of every core PHP function.
+
+```php
+// This code is incorrect. Twice.
+// "file_get_contents" can return false if the file does not exists
+// "json_decode" can return false if the file content is not valid JSON
+$content = file_get_contents('foobar.json');
+$foobar = json_decode($content);
+```
+
+The correct version of this code would be:
+
+```php
+$content = file_get_contents('foobar.json');
+if ($content === false) {
+ throw new FileLoadingException('Could not load file foobar.json');
+}
+$foobar = json_decode($content);
+if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new FileLoadingException('foobar.json does not contain valid JSON: '.json_last_error_msg());
+}
+```
+
+Obviously, while this snippet is correct, it is less easy to read.
+
+## The solution
+
+Enter *thecodingmachine/safe* aka Safe-PHP.
+
+Safe-PHP redeclares all core PHP functions. The new PHP functions act exactly as the old ones, except they
+throw exceptions properly when an error is encountered. The "safe" functions have the same name as the core PHP
+functions, except they are in the `Safe` namespace.
+
+```php
+use function Safe\file_get_contents;
+use function Safe\json_decode;
+
+// This code is both safe and simple!
+$content = file_get_contents('foobar.json');
+$foobar = json_decode($content);
+```
+
+All PHP functions that can return `false` on error are part of Safe.
+In addition, Safe also provide 2 'Safe' classes: `Safe\DateTime` and `Safe\DateTimeImmutable` whose methods will throw exceptions instead of returning false.
+
+## PHPStan integration
+
+> Yeah... but I must explicitly think about importing the "safe" variant of the function, for each and every file of my application.
+> I'm sure I will forget some "use function" statements!
+
+Fear not! thecodingmachine/safe comes with a PHPStan rule.
+
+Never heard of [PHPStan](https://github.com/phpstan/phpstan) before?
+Check it out, it's an amazing code analyzer for PHP.
+
+Simply install the Safe rule in your PHPStan setup (explained in the "Installation" section) and PHPStan will let you know each time you are using an "unsafe" function.
+
+The code below will trigger this warning:
+
+```php
+$content = file_get_contents('foobar.json');
+```
+
+> Function file_get_contents is unsafe to use. It can return FALSE instead of throwing an exception. Please add 'use function Safe\\file_get_contents;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library.
+
+## Installation
+
+Use composer to install Safe-PHP:
+
+```bash
+$ composer require thecodingmachine/safe
+```
+
+*Highly recommended*: install PHPStan and PHPStan extension:
+
+```bash
+$ composer require --dev thecodingmachine/phpstan-safe-rule
+```
+
+Now, edit your `phpstan.neon` file and add these rules:
+
+```yml
+includes:
+ - vendor/thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon
+```
+
+## Automated refactoring
+
+You have a large legacy codebase and want to use "Safe-PHP" functions throughout your project? PHPStan will help you
+find these functions but changing the namespace of the functions one function at a time might be a tedious task.
+
+Fortunately, Safe comes bundled with a "Rector" configuration file. [Rector](https://github.com/rectorphp/rector) is a command-line
+tool that performs instant refactoring of your application.
+
+Run
+
+```bash
+$ composer require --dev rector/rector:^0.7
+```
+
+to install `rector/rector`.
+
+Run
+
+```bash
+vendor/bin/rector process src/ --config vendor/thecodingmachine/safe/rector-migrate-0.7.php
+```
+
+to run `rector/rector`.
+
+*Note:* do not forget to replace "src/" with the path to your source directory.
+
+**Important:** the refactoring only performs a "dumb" replacement of functions. It will not modify the way
+"false" return values are handled. So if your code was already performing error handling, you will have to deal
+with it manually.
+
+Especially, you should look for error handling that was already performed, like:
+
+```php
+if (!mkdir($dirPath)) {
+ // Do something on error
+}
+```
+
+This code will be refactored by Rector to:
+
+```php
+if (!\Safe\mkdir($dirPath)) {
+ // Do something on error
+}
+```
+
+You should then (manually) refactor it to:
+
+```php
+try {
+ \Safe\mkdir($dirPath));
+} catch (\Safe\FilesystemException $e) {
+ // Do something on error
+}
+```
+
+## Performance impact
+
+Safe is loading 1000+ functions from ~85 files on each request. Yet, the performance impact of this loading is quite low.
+
+In case you worry, using Safe will "cost" you ~700µs on each request. The [performance section](performance/README.md)
+contains more information regarding the way we tested the performance impact of Safe.
+
+## Learn more
+
+Read [the release article on TheCodingMachine's blog](https://thecodingmachine.io/introducing-safe-php) if you want to
+learn more about what triggered the development of Safe-PHP.
+
+## Contributing
+
+The files that contain all the functions are auto-generated from the PHP doc.
+Read the [CONTRIBUTING.md](CONTRIBUTING.md) file to learn how to regenerate these files and to contribute to this library.
diff --git a/thecodingmachine/safe/composer.json b/thecodingmachine/safe/composer.json
new file mode 100644
index 000000000..2cd03fcc8
--- /dev/null
+++ b/thecodingmachine/safe/composer.json
@@ -0,0 +1,123 @@
+{
+ "name": "thecodingmachine/safe",
+ "description": "PHP core functions that throw exceptions instead of returning FALSE on error",
+ "license": "MIT",
+ "autoload": {
+ "psr-4": {
+ "Safe\\": [
+ "lib/",
+ "deprecated/",
+ "generated/"
+ ]
+ },
+ "files": [
+ "deprecated/apc.php",
+ "deprecated/libevent.php",
+ "deprecated/mssql.php",
+ "deprecated/stats.php",
+ "lib/special_cases.php",
+ "generated/apache.php",
+ "generated/apcu.php",
+ "generated/array.php",
+ "generated/bzip2.php",
+ "generated/calendar.php",
+ "generated/classobj.php",
+ "generated/com.php",
+ "generated/cubrid.php",
+ "generated/curl.php",
+ "generated/datetime.php",
+ "generated/dir.php",
+ "generated/eio.php",
+ "generated/errorfunc.php",
+ "generated/exec.php",
+ "generated/fileinfo.php",
+ "generated/filesystem.php",
+ "generated/filter.php",
+ "generated/fpm.php",
+ "generated/ftp.php",
+ "generated/funchand.php",
+ "generated/gmp.php",
+ "generated/gnupg.php",
+ "generated/hash.php",
+ "generated/ibase.php",
+ "generated/ibmDb2.php",
+ "generated/iconv.php",
+ "generated/image.php",
+ "generated/imap.php",
+ "generated/info.php",
+ "generated/ingres-ii.php",
+ "generated/inotify.php",
+ "generated/json.php",
+ "generated/ldap.php",
+ "generated/libxml.php",
+ "generated/lzf.php",
+ "generated/mailparse.php",
+ "generated/mbstring.php",
+ "generated/misc.php",
+ "generated/msql.php",
+ "generated/mysql.php",
+ "generated/mysqli.php",
+ "generated/mysqlndMs.php",
+ "generated/mysqlndQc.php",
+ "generated/network.php",
+ "generated/oci8.php",
+ "generated/opcache.php",
+ "generated/openssl.php",
+ "generated/outcontrol.php",
+ "generated/password.php",
+ "generated/pcntl.php",
+ "generated/pcre.php",
+ "generated/pdf.php",
+ "generated/pgsql.php",
+ "generated/posix.php",
+ "generated/ps.php",
+ "generated/pspell.php",
+ "generated/readline.php",
+ "generated/rpminfo.php",
+ "generated/rrd.php",
+ "generated/sem.php",
+ "generated/session.php",
+ "generated/shmop.php",
+ "generated/simplexml.php",
+ "generated/sockets.php",
+ "generated/sodium.php",
+ "generated/solr.php",
+ "generated/spl.php",
+ "generated/sqlsrv.php",
+ "generated/ssdeep.php",
+ "generated/ssh2.php",
+ "generated/stream.php",
+ "generated/strings.php",
+ "generated/swoole.php",
+ "generated/uodbc.php",
+ "generated/uopz.php",
+ "generated/url.php",
+ "generated/var.php",
+ "generated/xdiff.php",
+ "generated/xml.php",
+ "generated/xmlrpc.php",
+ "generated/yaml.php",
+ "generated/yaz.php",
+ "generated/zip.php",
+ "generated/zlib.php"
+ ]
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^0.12",
+ "thecodingmachine/phpstan-strict-rules": "^0.12",
+ "squizlabs/php_codesniffer": "^3.2"
+ },
+ "scripts": {
+ "phpstan": "phpstan analyse lib -c phpstan.neon --level=max --no-progress -vvv",
+ "cs-fix": "phpcbf",
+ "cs-check": "phpcs"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.1-dev"
+ }
+ }
+}
\ No newline at end of file
diff --git a/thecodingmachine/safe/deprecated/Exceptions/ApcException.php b/thecodingmachine/safe/deprecated/Exceptions/ApcException.php
new file mode 100644
index 000000000..f344490d8
--- /dev/null
+++ b/thecodingmachine/safe/deprecated/Exceptions/ApcException.php
@@ -0,0 +1,11 @@
+
+ *
+ *
+ *
+ * The mode parameter consists of three octal
+ * number components specifying access restrictions for the owner,
+ * the user group in which the owner is in, and to everybody else in
+ * this order. One component can be computed by adding up the needed
+ * permissions for that target user base. Number 1 means that you
+ * grant execute rights, number 2 means that you make the file
+ * writeable, number 4 means that you make the file readable. Add
+ * up these numbers to specify needed rights. You can also read more
+ * about modes on Unix systems with 'man 1 chmod'
+ * and 'man 2 chmod'.
+ *
+ *
+ *
+ *
+ */
+function chmod(string $filename, int $mode): void
+{
+ error_clear_last();
+ $result = \chmod($filename, $mode);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Attempts to change the owner of the file filename
+ * to user user. Only the superuser may change the
+ * owner of a file.
+ *
+ * @param string $filename Path to the file.
+ * @param string|int $user A user name or number.
+ * @throws FilesystemException
+ *
+ */
+function chown(string $filename, $user): void
+{
+ error_clear_last();
+ $result = \chown($filename, $user);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Makes a copy of the file source to
+ * dest.
+ *
+ * If you wish to move a file, use the rename function.
+ *
+ * @param string $source Path to the source file.
+ * @param string $dest The destination path. If dest is a URL, the
+ * copy operation may fail if the wrapper does not support overwriting of
+ * existing files.
+ *
+ * If the destination file already exists, it will be overwritten.
+ * @param resource $context A valid context resource created with
+ * stream_context_create.
+ * @throws FilesystemException
+ *
+ */
+function copy(string $source, string $dest, $context = null): void
+{
+ error_clear_last();
+ if ($context !== null) {
+ $result = \copy($source, $dest, $context);
+ } else {
+ $result = \copy($source, $dest);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Given a string containing a directory, this function will return the
+ * number of bytes available on the corresponding filesystem or disk
+ * partition.
+ *
+ * @param string $directory A directory of the filesystem or disk partition.
+ *
+ * Given a file name instead of a directory, the behaviour of the
+ * function is unspecified and may differ between operating systems and
+ * PHP versions.
+ * @return float Returns the number of available bytes as a float.
+ * @throws FilesystemException
+ *
+ */
+function disk_free_space(string $directory): float
+{
+ error_clear_last();
+ $result = \disk_free_space($directory);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Given a string containing a directory, this function will return the total
+ * number of bytes on the corresponding filesystem or disk partition.
+ *
+ * @param string $directory A directory of the filesystem or disk partition.
+ * @return float Returns the total number of bytes as a float.
+ * @throws FilesystemException
+ *
+ */
+function disk_total_space(string $directory): float
+{
+ error_clear_last();
+ $result = \disk_total_space($directory);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * The file pointed to by handle is closed.
+ *
+ * @param resource $handle The file pointer must be valid, and must point to a file successfully
+ * opened by fopen or fsockopen.
+ * @throws FilesystemException
+ *
+ */
+function fclose($handle): void
+{
+ error_clear_last();
+ $result = \fclose($handle);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * This function forces a write of all buffered output to the resource
+ * pointed to by the file handle.
+ *
+ * @param resource $handle The file pointer must be valid, and must point to
+ * a file successfully opened by fopen or
+ * fsockopen (and not yet closed by
+ * fclose).
+ * @throws FilesystemException
+ *
+ */
+function fflush($handle): void
+{
+ error_clear_last();
+ $result = \fflush($handle);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * This function is similar to file, except that
+ * file_get_contents returns the file in a
+ * string, starting at the specified offset
+ * up to maxlen bytes. On failure,
+ * file_get_contents will return FALSE.
+ *
+ * file_get_contents is the preferred way to read the
+ * contents of a file into a string. It will use memory mapping techniques if
+ * supported by your OS to enhance performance.
+ *
+ * @param string $filename Name of the file to read.
+ * @param bool $use_include_path The FILE_USE_INCLUDE_PATH constant can be used
+ * to trigger include path
+ * search.
+ * This is not possible if strict typing
+ * is enabled, since FILE_USE_INCLUDE_PATH is an
+ * int. Use TRUE instead.
+ * @param resource|null $context A valid context resource created with
+ * stream_context_create. If you don't need to use a
+ * custom context, you can skip this parameter by NULL.
+ * @param int $offset The offset where the reading starts on the original stream.
+ * Negative offsets count from the end of the stream.
+ *
+ * Seeking (offset) is not supported with remote files.
+ * Attempting to seek on non-local files may work with small offsets, but this
+ * is unpredictable because it works on the buffered stream.
+ * @param int $maxlen Maximum length of data read. The default is to read until end
+ * of file is reached. Note that this parameter is applied to the
+ * stream processed by the filters.
+ * @return string The function returns the read data.
+ * @throws FilesystemException
+ *
+ */
+function file_get_contents(string $filename, bool $use_include_path = false, $context = null, int $offset = 0, int $maxlen = null): string
+{
+ error_clear_last();
+ if ($maxlen !== null) {
+ $result = \file_get_contents($filename, $use_include_path, $context, $offset, $maxlen);
+ } elseif ($offset !== 0) {
+ $result = \file_get_contents($filename, $use_include_path, $context, $offset);
+ } elseif ($context !== null) {
+ $result = \file_get_contents($filename, $use_include_path, $context);
+ } else {
+ $result = \file_get_contents($filename, $use_include_path);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * This function is identical to calling fopen,
+ * fwrite and fclose successively
+ * to write data to a file.
+ *
+ * If filename does not exist, the file is created.
+ * Otherwise, the existing file is overwritten, unless the
+ * FILE_APPEND flag is set.
+ *
+ * @param string $filename Path to the file where to write the data.
+ * @param mixed $data The data to write. Can be either a string, an
+ * array or a stream resource.
+ *
+ * If data is a stream resource, the
+ * remaining buffer of that stream will be copied to the specified file.
+ * This is similar with using stream_copy_to_stream.
+ *
+ * You can also specify the data parameter as a single
+ * dimension array. This is equivalent to
+ * file_put_contents($filename, implode('', $array)).
+ * @param int $flags The value of flags can be any combination of
+ * the following flags, joined with the binary OR (|)
+ * operator.
+ *
+ *
+ * Available flags
+ *
+ *
+ *
+ * Flag
+ * Description
+ *
+ *
+ *
+ *
+ *
+ * FILE_USE_INCLUDE_PATH
+ *
+ *
+ * Search for filename in the include directory.
+ * See include_path for more
+ * information.
+ *
+ *
+ *
+ *
+ * FILE_APPEND
+ *
+ *
+ * If file filename already exists, append
+ * the data to the file instead of overwriting it.
+ *
+ *
+ *
+ *
+ * LOCK_EX
+ *
+ *
+ * Acquire an exclusive lock on the file while proceeding to the
+ * writing. In other words, a flock call happens
+ * between the fopen call and the
+ * fwrite call. This is not identical to an
+ * fopen call with mode "x".
+ *
+ *
+ *
+ *
+ *
+ * @param resource $context A valid context resource created with
+ * stream_context_create.
+ * @return int This function returns the number of bytes that were written to the file.
+ * @throws FilesystemException
+ *
+ */
+function file_put_contents(string $filename, $data, int $flags = 0, $context = null): int
+{
+ error_clear_last();
+ if ($context !== null) {
+ $result = \file_put_contents($filename, $data, $flags, $context);
+ } else {
+ $result = \file_put_contents($filename, $data, $flags);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Reads an entire file into an array.
+ *
+ * @param string $filename Path to the file.
+ * @param int $flags The optional parameter flags can be one, or
+ * more, of the following constants:
+ *
+ *
+ *
+ * FILE_USE_INCLUDE_PATH
+ *
+ *
+ *
+ * Search for the file in the include_path.
+ *
+ *
+ *
+ *
+ *
+ * FILE_IGNORE_NEW_LINES
+ *
+ *
+ *
+ * Omit newline at the end of each array element
+ *
+ *
+ *
+ *
+ *
+ * FILE_SKIP_EMPTY_LINES
+ *
+ *
+ *
+ * Skip empty lines
+ *
+ *
+ *
+ *
+ * @param resource $context
+ * @return array Returns the file in an array. Each element of the array corresponds to a
+ * line in the file, with the newline still attached. Upon failure,
+ * file returns FALSE.
+ * @throws FilesystemException
+ *
+ */
+function file(string $filename, int $flags = 0, $context = null): array
+{
+ error_clear_last();
+ if ($context !== null) {
+ $result = \file($filename, $flags, $context);
+ } else {
+ $result = \file($filename, $flags);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ *
+ *
+ * @param string $filename Path to the file.
+ * @return int Returns the time the file was last accessed.
+ * The time is returned as a Unix timestamp.
+ * @throws FilesystemException
+ *
+ */
+function fileatime(string $filename): int
+{
+ error_clear_last();
+ $result = \fileatime($filename);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Gets the inode change time of a file.
+ *
+ * @param string $filename Path to the file.
+ * @return int Returns the time the file was last changed.
+ * The time is returned as a Unix timestamp.
+ * @throws FilesystemException
+ *
+ */
+function filectime(string $filename): int
+{
+ error_clear_last();
+ $result = \filectime($filename);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Gets the file inode.
+ *
+ * @param string $filename Path to the file.
+ * @return int Returns the inode number of the file.
+ * @throws FilesystemException
+ *
+ */
+function fileinode(string $filename): int
+{
+ error_clear_last();
+ $result = \fileinode($filename);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * This function returns the time when the data blocks of a file were being
+ * written to, that is, the time when the content of the file was changed.
+ *
+ * @param string $filename Path to the file.
+ * @return int Returns the time the file was last modified.
+ * The time is returned as a Unix timestamp, which is
+ * suitable for the date function.
+ * @throws FilesystemException
+ *
+ */
+function filemtime(string $filename): int
+{
+ error_clear_last();
+ $result = \filemtime($filename);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Gets the file owner.
+ *
+ * @param string $filename Path to the file.
+ * @return int Returns the user ID of the owner of the file.
+ * The user ID is returned in numerical format, use
+ * posix_getpwuid to resolve it to a username.
+ * @throws FilesystemException
+ *
+ */
+function fileowner(string $filename): int
+{
+ error_clear_last();
+ $result = \fileowner($filename);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Gets the size for the given file.
+ *
+ * @param string $filename Path to the file.
+ * @return int Returns the size of the file in bytes, or FALSE (and generates an error
+ * of level E_WARNING) in case of an error.
+ * @throws FilesystemException
+ *
+ */
+function filesize(string $filename): int
+{
+ error_clear_last();
+ $result = \filesize($filename);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * flock allows you to perform a simple reader/writer
+ * model which can be used on virtually every platform (including most Unix
+ * derivatives and even Windows).
+ *
+ * On versions of PHP before 5.3.2, the lock is released also by
+ * fclose (which is also called automatically when script
+ * finished).
+ *
+ * PHP supports a portable way of locking complete files in an advisory way
+ * (which means all accessing programs have to use the same way of locking
+ * or it will not work). By default, this function will block until the
+ * requested lock is acquired; this may be controlled with the LOCK_NB option documented below.
+ *
+ * @param resource $handle A file system pointer resource
+ * that is typically created using fopen.
+ * @param int $operation operation is one of the following:
+ *
+ *
+ *
+ * LOCK_SH to acquire a shared lock (reader).
+ *
+ *
+ *
+ *
+ * LOCK_EX to acquire an exclusive lock (writer).
+ *
+ *
+ *
+ *
+ * LOCK_UN to release a lock (shared or exclusive).
+ *
+ *
+ *
+ *
+ * It is also possible to add LOCK_NB as a bitmask to one
+ * of the above operations, if flock should not
+ * block during the locking attempt.
+ * @param int|null $wouldblock The optional third argument is set to 1 if the lock would block
+ * (EWOULDBLOCK errno condition).
+ * @throws FilesystemException
+ *
+ */
+function flock($handle, int $operation, ?int &$wouldblock = null): void
+{
+ error_clear_last();
+ $result = \flock($handle, $operation, $wouldblock);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * fopen binds a named resource, specified by
+ * filename, to a stream.
+ *
+ * @param string $filename If filename is of the form "scheme://...", it
+ * is assumed to be a URL and PHP will search for a protocol handler
+ * (also known as a wrapper) for that scheme. If no wrappers for that
+ * protocol are registered, PHP will emit a notice to help you track
+ * potential problems in your script and then continue as though
+ * filename specifies a regular file.
+ *
+ * If PHP has decided that filename specifies
+ * a local file, then it will try to open a stream on that file.
+ * The file must be accessible to PHP, so you need to ensure that
+ * the file access permissions allow this access.
+ * If you have enabled
+ * open_basedir further
+ * restrictions may apply.
+ *
+ * If PHP has decided that filename specifies
+ * a registered protocol, and that protocol is registered as a
+ * network URL, PHP will check to make sure that
+ * allow_url_fopen is
+ * enabled. If it is switched off, PHP will emit a warning and
+ * the fopen call will fail.
+ *
+ * The list of supported protocols can be found in . Some protocols (also referred to as
+ * wrappers) support context
+ * and/or php.ini options. Refer to the specific page for the
+ * protocol in use for a list of options which can be set. (e.g.
+ * php.ini value user_agent used by the
+ * http wrapper).
+ *
+ * On the Windows platform, be careful to escape any backslashes
+ * used in the path to the file, or use forward slashes.
+ *
+ *
+ *
+ * ]]>
+ *
+ *
+ * @param string $mode The mode parameter specifies the type of access
+ * you require to the stream. It may be any of the following:
+ *
+ *
+ * A list of possible modes for fopen
+ * using mode
+ *
+ *
+ *
+ *
+ * mode
+ * Description
+ *
+ *
+ *
+ *
+ * 'r'
+ *
+ * Open for reading only; place the file pointer at the
+ * beginning of the file.
+ *
+ *
+ *
+ * 'r+'
+ *
+ * Open for reading and writing; place the file pointer at
+ * the beginning of the file.
+ *
+ *
+ *
+ * 'w'
+ *
+ * Open for writing only; place the file pointer at the
+ * beginning of the file and truncate the file to zero length.
+ * If the file does not exist, attempt to create it.
+ *
+ *
+ *
+ * 'w+'
+ *
+ * Open for reading and writing; place the file pointer at
+ * the beginning of the file and truncate the file to zero
+ * length. If the file does not exist, attempt to create it.
+ *
+ *
+ *
+ * 'a'
+ *
+ * Open for writing only; place the file pointer at the end of
+ * the file. If the file does not exist, attempt to create it.
+ * In this mode, fseek has no effect, writes are always appended.
+ *
+ *
+ *
+ * 'a+'
+ *
+ * Open for reading and writing; place the file pointer at
+ * the end of the file. If the file does not exist, attempt to
+ * create it. In this mode, fseek only affects
+ * the reading position, writes are always appended.
+ *
+ *
+ *
+ * 'x'
+ *
+ * Create and open for writing only; place the file pointer at the
+ * beginning of the file. If the file already exists, the
+ * fopen call will fail by returning FALSE and
+ * generating an error of level E_WARNING. If
+ * the file does not exist, attempt to create it. This is equivalent
+ * to specifying O_EXCL|O_CREAT flags for the
+ * underlying open(2) system call.
+ *
+ *
+ *
+ * 'x+'
+ *
+ * Create and open for reading and writing; otherwise it has the
+ * same behavior as 'x'.
+ *
+ *
+ *
+ * 'c'
+ *
+ * Open the file for writing only. If the file does not exist, it is
+ * created. If it exists, it is neither truncated (as opposed to
+ * 'w'), nor the call to this function fails (as is
+ * the case with 'x'). The file pointer is
+ * positioned on the beginning of the file. This may be useful if it's
+ * desired to get an advisory lock (see flock)
+ * before attempting to modify the file, as using
+ * 'w' could truncate the file before the lock
+ * was obtained (if truncation is desired,
+ * ftruncate can be used after the lock is
+ * requested).
+ *
+ *
+ *
+ * 'c+'
+ *
+ * Open the file for reading and writing; otherwise it has the same
+ * behavior as 'c'.
+ *
+ *
+ *
+ * 'e'
+ *
+ * Set close-on-exec flag on the opened file descriptor. Only
+ * available in PHP compiled on POSIX.1-2008 conform systems.
+ *
+ *
+ *
+ *
+ *
+ *
+ * Different operating system families have different line-ending
+ * conventions. When you write a text file and want to insert a line
+ * break, you need to use the correct line-ending character(s) for your
+ * operating system. Unix based systems use \n as the
+ * line ending character, Windows based systems use \r\n
+ * as the line ending characters and Macintosh based systems (Mac OS Classic) used
+ * \r as the line ending character.
+ *
+ * If you use the wrong line ending characters when writing your files, you
+ * might find that other applications that open those files will "look
+ * funny".
+ *
+ * Windows offers a text-mode translation flag ('t')
+ * which will transparently translate \n to
+ * \r\n when working with the file. In contrast, you
+ * can also use 'b' to force binary mode, which will not
+ * translate your data. To use these flags, specify either
+ * 'b' or 't' as the last character
+ * of the mode parameter.
+ *
+ * The default translation mode is 'b'.
+ * You can use the 't'
+ * mode if you are working with plain-text files and you use
+ * \n to delimit your line endings in your script, but
+ * expect your files to be readable with applications such as old versions of notepad. You
+ * should use the 'b' in all other cases.
+ *
+ * If you specify the 't' flag when working with binary files, you
+ * may experience strange problems with your data, including broken image
+ * files and strange problems with \r\n characters.
+ *
+ * For portability, it is also strongly recommended that
+ * you re-write code that uses or relies upon the 't'
+ * mode so that it uses the correct line endings and
+ * 'b' mode instead.
+ * @param bool $use_include_path The optional third use_include_path parameter
+ * can be set to '1' or TRUE if you want to search for the file in the
+ * include_path, too.
+ * @param resource $context
+ * @return resource Returns a file pointer resource on success
+ * @throws FilesystemException
+ *
+ */
+function fopen(string $filename, string $mode, bool $use_include_path = false, $context = null)
+{
+ error_clear_last();
+ if ($context !== null) {
+ $result = \fopen($filename, $mode, $use_include_path, $context);
+ } else {
+ $result = \fopen($filename, $mode, $use_include_path);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * fputcsv formats a line (passed as a
+ * fields array) as CSV and writes it (terminated by a
+ * newline) to the specified file handle.
+ *
+ * @param resource $handle The file pointer must be valid, and must point to
+ * a file successfully opened by fopen or
+ * fsockopen (and not yet closed by
+ * fclose).
+ * @param array $fields An array of strings.
+ * @param string $delimiter The optional delimiter parameter sets the field
+ * delimiter (one character only).
+ * @param string $enclosure The optional enclosure parameter sets the field
+ * enclosure (one character only).
+ * @param string $escape_char The optional escape_char parameter sets the
+ * escape character (at most one character).
+ * An empty string ("") disables the proprietary escape mechanism.
+ * @return int Returns the length of the written string.
+ * @throws FilesystemException
+ *
+ */
+function fputcsv($handle, array $fields, string $delimiter = ",", string $enclosure = '"', string $escape_char = "\\"): int
+{
+ error_clear_last();
+ $result = \fputcsv($handle, $fields, $delimiter, $enclosure, $escape_char);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * fread reads up to
+ * length bytes from the file pointer
+ * referenced by handle. Reading stops as soon as one
+ * of the following conditions is met:
+ *
+ *
+ *
+ * length bytes have been read
+ *
+ *
+ *
+ *
+ * EOF (end of file) is reached
+ *
+ *
+ *
+ *
+ * a packet becomes available or the
+ * socket timeout occurs (for network streams)
+ *
+ *
+ *
+ *
+ * if the stream is read buffered and it does not represent a plain file, at
+ * most one read of up to a number of bytes equal to the chunk size (usually
+ * 8192) is made; depending on the previously buffered data, the size of the
+ * returned data may be larger than the chunk size.
+ *
+ *
+ *
+ *
+ * @param resource $handle A file system pointer resource
+ * that is typically created using fopen.
+ * @param int $length Up to length number of bytes read.
+ * @return string Returns the read string.
+ * @throws FilesystemException
+ *
+ */
+function fread($handle, int $length): string
+{
+ error_clear_last();
+ $result = \fread($handle, $length);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Takes the filepointer, handle, and truncates the file to
+ * length, size.
+ *
+ * @param resource $handle The file pointer.
+ *
+ * The handle must be open for writing.
+ * @param int $size The size to truncate to.
+ *
+ * If size is larger than the file then the file
+ * is extended with null bytes.
+ *
+ * If size is smaller than the file then the file
+ * is truncated to that size.
+ * @throws FilesystemException
+ *
+ */
+function ftruncate($handle, int $size): void
+{
+ error_clear_last();
+ $result = \ftruncate($handle, $size);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ *
+ *
+ * @param resource $handle A file system pointer resource
+ * that is typically created using fopen.
+ * @param string $string The string that is to be written.
+ * @param int $length If the length argument is given, writing will
+ * stop after length bytes have been written or
+ * the end of string is reached, whichever comes
+ * first.
+ *
+ * Note that if the length argument is given,
+ * then the magic_quotes_runtime
+ * configuration option will be ignored and no slashes will be
+ * stripped from string.
+ * @return int
+ * @throws FilesystemException
+ *
+ */
+function fwrite($handle, string $string, int $length = null): int
+{
+ error_clear_last();
+ if ($length !== null) {
+ $result = \fwrite($handle, $string, $length);
+ } else {
+ $result = \fwrite($handle, $string);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * The glob function searches for all the pathnames
+ * matching pattern according to the rules used by
+ * the libc glob() function, which is similar to the rules used by common
+ * shells.
+ *
+ * @param string $pattern The pattern. No tilde expansion or parameter substitution is done.
+ *
+ * Special characters:
+ *
+ *
+ *
+ * * - Matches zero or more characters.
+ *
+ *
+ *
+ *
+ * ? - Matches exactly one character (any character).
+ *
+ *
+ *
+ *
+ * [...] - Matches one character from a group of
+ * characters. If the first character is !,
+ * matches any character not in the group.
+ *
+ *
+ *
+ *
+ * \ - Escapes the following character,
+ * except when the GLOB_NOESCAPE flag is used.
+ *
+ *
+ *
+ * @param int $flags Valid flags:
+ *
+ *
+ *
+ * GLOB_MARK - Adds a slash (a backslash on Windows) to each directory returned
+ *
+ *
+ *
+ *
+ * GLOB_NOSORT - Return files as they appear in the
+ * directory (no sorting). When this flag is not used, the pathnames are
+ * sorted alphabetically
+ *
+ *
+ *
+ *
+ * GLOB_NOCHECK - Return the search pattern if no
+ * files matching it were found
+ *
+ *
+ *
+ *
+ * GLOB_NOESCAPE - Backslashes do not quote
+ * metacharacters
+ *
+ *
+ *
+ *
+ * GLOB_BRACE - Expands {a,b,c} to match 'a', 'b',
+ * or 'c'
+ *
+ *
+ *
+ *
+ * GLOB_ONLYDIR - Return only directory entries
+ * which match the pattern
+ *
+ *
+ *
+ *
+ * GLOB_ERR - Stop on read errors (like unreadable
+ * directories), by default errors are ignored.
+ *
+ *
+ *
+ * @return array Returns an array containing the matched files/directories, an empty array
+ * if no file matched.
+ * @throws FilesystemException
+ *
+ */
+function glob(string $pattern, int $flags = 0): array
+{
+ error_clear_last();
+ $result = \glob($pattern, $flags);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Attempts to change the group of the symlink filename
+ * to group.
+ *
+ * Only the superuser may change the group of a symlink arbitrarily; other
+ * users may change the group of a symlink to any group of which that user is
+ * a member.
+ *
+ * @param string $filename Path to the symlink.
+ * @param string|int $group The group specified by name or number.
+ * @throws FilesystemException
+ *
+ */
+function lchgrp(string $filename, $group): void
+{
+ error_clear_last();
+ $result = \lchgrp($filename, $group);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Attempts to change the owner of the symlink filename
+ * to user user.
+ *
+ * Only the superuser may change the owner of a symlink.
+ *
+ * @param string $filename Path to the file.
+ * @param string|int $user User name or number.
+ * @throws FilesystemException
+ *
+ */
+function lchown(string $filename, $user): void
+{
+ error_clear_last();
+ $result = \lchown($filename, $user);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * link creates a hard link.
+ *
+ * @param string $target Target of the link.
+ * @param string $link The link name.
+ * @throws FilesystemException
+ *
+ */
+function link(string $target, string $link): void
+{
+ error_clear_last();
+ $result = \link($target, $link);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Attempts to create the directory specified by pathname.
+ *
+ * @param string $pathname The directory path.
+ * @param int $mode The mode is 0777 by default, which means the widest possible
+ * access. For more information on modes, read the details
+ * on the chmod page.
+ *
+ * mode is ignored on Windows.
+ *
+ * Note that you probably want to specify the mode as an octal number,
+ * which means it should have a leading zero. The mode is also modified
+ * by the current umask, which you can change using
+ * umask.
+ * @param bool $recursive Allows the creation of nested directories specified in the
+ * pathname.
+ * @param resource $context
+ * @throws FilesystemException
+ *
+ */
+function mkdir(string $pathname, int $mode = 0777, bool $recursive = false, $context = null): void
+{
+ error_clear_last();
+ if ($context !== null) {
+ $result = \mkdir($pathname, $mode, $recursive, $context);
+ } else {
+ $result = \mkdir($pathname, $mode, $recursive);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * parse_ini_file loads in the
+ * ini file specified in filename,
+ * and returns the settings in it in an associative array.
+ *
+ * The structure of the ini file is the same as the php.ini's.
+ *
+ * @param string $filename The filename of the ini file being parsed. If a relative path is used,
+ * it is evaluated relative to the current working directory, then the
+ * include_path.
+ * @param bool $process_sections By setting the process_sections
+ * parameter to TRUE, you get a multidimensional array, with
+ * the section names and settings included. The default
+ * for process_sections is FALSE
+ * @param int $scanner_mode Can either be INI_SCANNER_NORMAL (default) or
+ * INI_SCANNER_RAW. If INI_SCANNER_RAW
+ * is supplied, then option values will not be parsed.
+ *
+ *
+ * As of PHP 5.6.1 can also be specified as INI_SCANNER_TYPED.
+ * In this mode boolean, null and integer types are preserved when possible.
+ * String values "true", "on" and "yes"
+ * are converted to TRUE. "false", "off", "no"
+ * and "none" are considered FALSE. "null" is converted to NULL
+ * in typed mode. Also, all numeric strings are converted to integer type if it is possible.
+ * @return array The settings are returned as an associative array on success.
+ * @throws FilesystemException
+ *
+ */
+function parse_ini_file(string $filename, bool $process_sections = false, int $scanner_mode = INI_SCANNER_NORMAL): array
+{
+ error_clear_last();
+ $result = \parse_ini_file($filename, $process_sections, $scanner_mode);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * parse_ini_string returns the settings in string
+ * ini in an associative array.
+ *
+ * The structure of the ini string is the same as the php.ini's.
+ *
+ * @param string $ini The contents of the ini file being parsed.
+ * @param bool $process_sections By setting the process_sections
+ * parameter to TRUE, you get a multidimensional array, with
+ * the section names and settings included. The default
+ * for process_sections is FALSE
+ * @param int $scanner_mode Can either be INI_SCANNER_NORMAL (default) or
+ * INI_SCANNER_RAW. If INI_SCANNER_RAW
+ * is supplied, then option values will not be parsed.
+ *
+ *
+ * As of PHP 5.6.1 can also be specified as INI_SCANNER_TYPED.
+ * In this mode boolean, null and integer types are preserved when possible.
+ * String values "true", "on" and "yes"
+ * are converted to TRUE. "false", "off", "no"
+ * and "none" are considered FALSE. "null" is converted to NULL
+ * in typed mode. Also, all numeric strings are converted to integer type if it is possible.
+ * @return array The settings are returned as an associative array on success.
+ * @throws FilesystemException
+ *
+ */
+function parse_ini_string(string $ini, bool $process_sections = false, int $scanner_mode = INI_SCANNER_NORMAL): array
+{
+ error_clear_last();
+ $result = \parse_ini_string($ini, $process_sections, $scanner_mode);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Reads a file and writes it to the output buffer.
+ *
+ * @param string $filename The filename being read.
+ * @param bool $use_include_path You can use the optional second parameter and set it to TRUE, if
+ * you want to search for the file in the include_path, too.
+ * @param resource $context A context stream resource.
+ * @return int Returns the number of bytes read from the file on success
+ * @throws FilesystemException
+ *
+ */
+function readfile(string $filename, bool $use_include_path = false, $context = null): int
+{
+ error_clear_last();
+ if ($context !== null) {
+ $result = \readfile($filename, $use_include_path, $context);
+ } else {
+ $result = \readfile($filename, $use_include_path);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * readlink does the same as the readlink C function.
+ *
+ * @param string $path The symbolic link path.
+ * @return string Returns the contents of the symbolic link path.
+ * @throws FilesystemException
+ *
+ */
+function readlink(string $path): string
+{
+ error_clear_last();
+ $result = \readlink($path);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * realpath expands all symbolic links and
+ * resolves references to /./, /../ and extra / characters in
+ * the input path and returns the canonicalized
+ * absolute pathname.
+ *
+ * @param string $path The path being checked.
+ *
+ *
+ * Whilst a path must be supplied, the value can be an empty string.
+ * In this case, the value is interpreted as the current directory.
+ *
+ *
+ *
+ * Whilst a path must be supplied, the value can be an empty string.
+ * In this case, the value is interpreted as the current directory.
+ * @return string Returns the canonicalized absolute pathname on success. The resulting path
+ * will have no symbolic link, /./ or /../ components. Trailing delimiters,
+ * such as \ and /, are also removed.
+ *
+ * realpath returns FALSE on failure, e.g. if
+ * the file does not exist.
+ * @throws FilesystemException
+ *
+ */
+function realpath(string $path): string
+{
+ error_clear_last();
+ $result = \realpath($path);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Attempts to rename oldname to
+ * newname, moving it between directories if necessary.
+ * If renaming a file and newname exists,
+ * it will be overwritten. If renaming a directory and
+ * newname exists,
+ * this function will emit a warning.
+ *
+ * @param string $oldname The old name.
+ *
+ * The wrapper used in oldname
+ * must match the wrapper used in
+ * newname.
+ * @param string $newname The new name.
+ * @param resource $context
+ * @throws FilesystemException
+ *
+ */
+function rename(string $oldname, string $newname, $context = null): void
+{
+ error_clear_last();
+ if ($context !== null) {
+ $result = \rename($oldname, $newname, $context);
+ } else {
+ $result = \rename($oldname, $newname);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Sets the file position indicator for handle
+ * to the beginning of the file stream.
+ *
+ * @param resource $handle The file pointer must be valid, and must point to a file
+ * successfully opened by fopen.
+ * @throws FilesystemException
+ *
+ */
+function rewind($handle): void
+{
+ error_clear_last();
+ $result = \rewind($handle);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Attempts to remove the directory named by dirname.
+ * The directory must be empty, and the relevant permissions must permit this.
+ * A E_WARNING level error will be generated on failure.
+ *
+ * @param string $dirname Path to the directory.
+ * @param resource $context
+ * @throws FilesystemException
+ *
+ */
+function rmdir(string $dirname, $context = null): void
+{
+ error_clear_last();
+ if ($context !== null) {
+ $result = \rmdir($dirname, $context);
+ } else {
+ $result = \rmdir($dirname);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * symlink creates a symbolic link to the existing
+ * target with the specified name
+ * link.
+ *
+ * @param string $target Target of the link.
+ * @param string $link The link name.
+ * @throws FilesystemException
+ *
+ */
+function symlink(string $target, string $link): void
+{
+ error_clear_last();
+ $result = \symlink($target, $link);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Creates a file with a unique filename, with access permission set to 0600, in the specified directory.
+ * If the directory does not exist or is not writable, tempnam may
+ * generate a file in the system's temporary directory, and return
+ * the full path to that file, including its name.
+ *
+ * @param string $dir The directory where the temporary filename will be created.
+ * @param string $prefix The prefix of the generated temporary filename.
+ * @return string Returns the new temporary filename (with path).
+ * @throws FilesystemException
+ *
+ */
+function tempnam(string $dir, string $prefix): string
+{
+ error_clear_last();
+ $result = \tempnam($dir, $prefix);
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Creates a temporary file with a unique name in read-write (w+) mode and
+ * returns a file handle.
+ *
+ * The file is automatically removed when closed (for example, by calling
+ * fclose, or when there are no remaining references to
+ * the file handle returned by tmpfile), or when the
+ * script ends.
+ *
+ * @return resource Returns a file handle, similar to the one returned by
+ * fopen, for the new file.
+ * @throws FilesystemException
+ *
+ */
+function tmpfile()
+{
+ error_clear_last();
+ $result = \tmpfile();
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Attempts to set the access and modification times of the file named in the
+ * filename parameter to the value given in
+ * time.
+ * Note that the access time is always modified, regardless of the number
+ * of parameters.
+ *
+ * If the file does not exist, it will be created.
+ *
+ * @param string $filename The name of the file being touched.
+ * @param int $time The touch time. If time is not supplied,
+ * the current system time is used.
+ * @param int $atime If present, the access time of the given filename is set to
+ * the value of atime. Otherwise, it is set to
+ * the value passed to the time parameter.
+ * If neither are present, the current system time is used.
+ * @throws FilesystemException
+ *
+ */
+function touch(string $filename, int $time = null, int $atime = null): void
+{
+ error_clear_last();
+ if ($atime !== null) {
+ $result = \touch($filename, $time, $atime);
+ } elseif ($time !== null) {
+ $result = \touch($filename, $time);
+ } else {
+ $result = \touch($filename);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Deletes filename. Similar to the Unix C unlink()
+ * function. An E_WARNING level error will be generated on
+ * failure.
+ *
+ * @param string $filename Path to the file.
+ * @param resource $context
+ * @throws FilesystemException
+ *
+ */
+function unlink(string $filename, $context = null): void
+{
+ error_clear_last();
+ if ($context !== null) {
+ $result = \unlink($filename, $context);
+ } else {
+ $result = \unlink($filename);
+ }
+ if ($result === false) {
+ throw FilesystemException::createFromPhpError();
+ }
+}
diff --git a/thecodingmachine/safe/generated/filter.php b/thecodingmachine/safe/generated/filter.php
new file mode 100644
index 000000000..2d836c6c9
--- /dev/null
+++ b/thecodingmachine/safe/generated/filter.php
@@ -0,0 +1,93 @@
+
+ *
+ *
+ *
+ * channels will be 3 for RGB pictures and 4 for CMYK
+ * pictures.
+ *
+ * bits is the number of bits for each color.
+ *
+ * For some image types, the presence of channels and
+ * bits values can be a bit
+ * confusing. As an example, GIF always uses 3 channels
+ * per pixel, but the number of bits per pixel cannot be calculated for an
+ * animated GIF with a global color table.
+ *
+ * On failure, FALSE is returned.
+ * @throws ImageException
+ *
+ */
+function getimagesize(string $filename, array &$imageinfo = null): array
+{
+ error_clear_last();
+ $result = \getimagesize($filename, $imageinfo);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * image2wbmp outputs or save a WBMP
+ * version of the given image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param string|null $filename Path to the saved file. If not given, the raw image stream will be
+ * output directly.
+ * @param int $foreground You can set the foreground color with this parameter by setting an
+ * identifier obtained from imagecolorallocate.
+ * The default foreground color is black.
+ * @throws ImageException
+ *
+ */
+function image2wbmp($image, ?string $filename = null, int $foreground = null): void
+{
+ error_clear_last();
+ if ($foreground !== null) {
+ $result = \image2wbmp($image, $filename, $foreground);
+ } elseif ($filename !== null) {
+ $result = \image2wbmp($image, $filename);
+ } else {
+ $result = \image2wbmp($image);
+ }
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ *
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param array $affine Array with keys 0 to 5.
+ * @param array $clip Array with keys "x", "y", "width" and "height".
+ * @return resource Return affined image resource on success.
+ * @throws ImageException
+ *
+ */
+function imageaffine($image, array $affine, array $clip = null)
+{
+ error_clear_last();
+ if ($clip !== null) {
+ $result = \imageaffine($image, $affine, $clip);
+ } else {
+ $result = \imageaffine($image, $affine);
+ }
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Returns the concatenation of two affine transformation matrices,
+ * what is useful if multiple transformations should be applied to the same
+ * image in one go.
+ *
+ * @param array $m1 An affine transformation matrix (an array with keys
+ * 0 to 5 and float values).
+ * @param array $m2 An affine transformation matrix (an array with keys
+ * 0 to 5 and float values).
+ * @return array{0:float,1:float,2:float,3:float,4:float,5:float} An affine transformation matrix (an array with keys
+ * 0 to 5 and float values).
+ * @throws ImageException
+ *
+ */
+function imageaffinematrixconcat(array $m1, array $m2): array
+{
+ error_clear_last();
+ $result = \imageaffinematrixconcat($m1, $m2);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Returns an affine transformation matrix.
+ *
+ * @param int $type One of the IMG_AFFINE_* constants.
+ * @param array|float $options If type is IMG_AFFINE_TRANSLATE
+ * or IMG_AFFINE_SCALE,
+ * options has to be an array with keys x
+ * and y, both having float values.
+ *
+ * If type is IMG_AFFINE_ROTATE,
+ * IMG_AFFINE_SHEAR_HORIZONTAL or IMG_AFFINE_SHEAR_VERTICAL,
+ * options has to be a float specifying the angle.
+ * @return array{0:float,1:float,2:float,3:float,4:float,5:float} An affine transformation matrix (an array with keys
+ * 0 to 5 and float values).
+ * @throws ImageException
+ *
+ */
+function imageaffinematrixget(int $type, $options = null): array
+{
+ error_clear_last();
+ if ($options !== null) {
+ $result = \imageaffinematrixget($type, $options);
+ } else {
+ $result = \imageaffinematrixget($type);
+ }
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagealphablending allows for two different
+ * modes of drawing on truecolor images. In blending mode, the
+ * alpha channel component of the color supplied to all drawing function,
+ * such as imagesetpixel determines how much of the
+ * underlying color should be allowed to shine through. As a result, gd
+ * automatically blends the existing color at that point with the drawing color,
+ * and stores the result in the image. The resulting pixel is opaque. In
+ * non-blending mode, the drawing color is copied literally with its alpha channel
+ * information, replacing the destination pixel. Blending mode is not available
+ * when drawing on palette images.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param bool $blendmode Whether to enable the blending mode or not. On true color images
+ * the default value is TRUE otherwise the default value is FALSE
+ * @throws ImageException
+ *
+ */
+function imagealphablending($image, bool $blendmode): void
+{
+ error_clear_last();
+ $result = \imagealphablending($image, $blendmode);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Activate the fast drawing antialiased methods for lines and wired polygons.
+ * It does not support alpha components. It works using a direct blend
+ * operation. It works only with truecolor images.
+ *
+ * Thickness and styled are not supported.
+ *
+ * Using antialiased primitives with transparent background color can end with
+ * some unexpected results. The blend method uses the background color as any
+ * other colors. The lack of alpha component support does not allow an alpha
+ * based antialiasing method.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param bool $enabled Whether to enable antialiasing or not.
+ * @throws ImageException
+ *
+ */
+function imageantialias($image, bool $enabled): void
+{
+ error_clear_last();
+ $result = \imageantialias($image, $enabled);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagearc draws an arc of circle centered at the given
+ * coordinates.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $cx x-coordinate of the center.
+ * @param int $cy y-coordinate of the center.
+ * @param int $width The arc width.
+ * @param int $height The arc height.
+ * @param int $start The arc start angle, in degrees.
+ * @param int $end The arc end angle, in degrees.
+ * 0° is located at the three-o'clock position, and the arc is drawn
+ * clockwise.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagearc($image, int $cx, int $cy, int $width, int $height, int $start, int $end, int $color): void
+{
+ error_clear_last();
+ $result = \imagearc($image, $cx, $cy, $width, $height, $start, $end, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Outputs or saves a BMP version of the given image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param mixed $to The path or an open stream resource (which is automatically being closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be outputted directly.
+ *
+ * NULL is invalid if the compressed arguments is
+ * not used.
+ * @param bool $compressed Whether the BMP should be compressed with run-length encoding (RLE), or not.
+ * @throws ImageException
+ *
+ */
+function imagebmp($image, $to = null, bool $compressed = true): void
+{
+ error_clear_last();
+ $result = \imagebmp($image, $to, $compressed);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagechar draws the first character of
+ * c in the image identified by
+ * image with its upper-left at
+ * x,y (top left is 0,
+ * 0) with the color color.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $font Can be 1, 2, 3, 4, 5 for built-in
+ * fonts in latin2 encoding (where higher numbers corresponding to larger fonts) or any of your
+ * own font identifiers registered with imageloadfont.
+ * @param int $x x-coordinate of the start.
+ * @param int $y y-coordinate of the start.
+ * @param string $c The character to draw.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagechar($image, int $font, int $x, int $y, string $c, int $color): void
+{
+ error_clear_last();
+ $result = \imagechar($image, $font, $x, $y, $c, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Draws the character c vertically at the specified
+ * coordinate on the given image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $font Can be 1, 2, 3, 4, 5 for built-in
+ * fonts in latin2 encoding (where higher numbers corresponding to larger fonts) or any of your
+ * own font identifiers registered with imageloadfont.
+ * @param int $x x-coordinate of the start.
+ * @param int $y y-coordinate of the start.
+ * @param string $c The character to draw.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagecharup($image, int $font, int $x, int $y, string $c, int $color): void
+{
+ error_clear_last();
+ $result = \imagecharup($image, $font, $x, $y, $c, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Returns the index of the color of the pixel at the
+ * specified location in the image specified by image.
+ *
+ * If the image is a
+ * truecolor image, this function returns the RGB value of that pixel as
+ * integer. Use bitshifting and masking to access the distinct red, green and blue
+ * component values:
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $x x-coordinate of the point.
+ * @param int $y y-coordinate of the point.
+ * @return int Returns the index of the color.
+ * @throws ImageException
+ *
+ */
+function imagecolorat($image, int $x, int $y): int
+{
+ error_clear_last();
+ $result = \imagecolorat($image, $x, $y);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * De-allocates a color previously allocated with
+ * imagecolorallocate or
+ * imagecolorallocatealpha.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $color The color identifier.
+ * @throws ImageException
+ *
+ */
+function imagecolordeallocate($image, int $color): void
+{
+ error_clear_last();
+ $result = \imagecolordeallocate($image, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Makes the colors of the palette version of an image more closely match the true color version.
+ *
+ * @param resource $image1 A truecolor image resource.
+ * @param resource $image2 A palette image resource pointing to an image that has the same
+ * size as image1.
+ * @throws ImageException
+ *
+ */
+function imagecolormatch($image1, $image2): void
+{
+ error_clear_last();
+ $result = \imagecolormatch($image1, $image2);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Applies a convolution matrix on the image, using the given coefficient and
+ * offset.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param array $matrix A 3x3 matrix: an array of three arrays of three floats.
+ * @param float $div The divisor of the result of the convolution, used for normalization.
+ * @param float $offset Color offset.
+ * @throws ImageException
+ *
+ */
+function imageconvolution($image, array $matrix, float $div, float $offset): void
+{
+ error_clear_last();
+ $result = \imageconvolution($image, $matrix, $div, $offset);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Copy a part of src_im onto
+ * dst_im starting at the x,y coordinates
+ * src_x, src_y with
+ * a width of src_w and a height of
+ * src_h. The portion defined will be copied
+ * onto the x,y coordinates, dst_x and
+ * dst_y.
+ *
+ * @param resource $dst_im Destination image resource.
+ * @param resource $src_im Source image resource.
+ * @param int $dst_x x-coordinate of destination point.
+ * @param int $dst_y y-coordinate of destination point.
+ * @param int $src_x x-coordinate of source point.
+ * @param int $src_y y-coordinate of source point.
+ * @param int $src_w Source width.
+ * @param int $src_h Source height.
+ * @throws ImageException
+ *
+ */
+function imagecopy($dst_im, $src_im, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_w, int $src_h): void
+{
+ error_clear_last();
+ $result = \imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Copy a part of src_im onto
+ * dst_im starting at the x,y coordinates
+ * src_x, src_y with
+ * a width of src_w and a height of
+ * src_h. The portion defined will be copied
+ * onto the x,y coordinates, dst_x and
+ * dst_y.
+ *
+ * @param resource $dst_im Destination image resource.
+ * @param resource $src_im Source image resource.
+ * @param int $dst_x x-coordinate of destination point.
+ * @param int $dst_y y-coordinate of destination point.
+ * @param int $src_x x-coordinate of source point.
+ * @param int $src_y y-coordinate of source point.
+ * @param int $src_w Source width.
+ * @param int $src_h Source height.
+ * @param int $pct The two images will be merged according to pct
+ * which can range from 0 to 100. When pct = 0,
+ * no action is taken, when 100 this function behaves identically
+ * to imagecopy for pallete images, except for
+ * ignoring alpha components, while it implements alpha transparency
+ * for true colour images.
+ * @throws ImageException
+ *
+ */
+function imagecopymerge($dst_im, $src_im, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_w, int $src_h, int $pct): void
+{
+ error_clear_last();
+ $result = \imagecopymerge($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagecopymergegray copy a part of src_im onto
+ * dst_im starting at the x,y coordinates
+ * src_x, src_y with
+ * a width of src_w and a height of
+ * src_h. The portion defined will be copied
+ * onto the x,y coordinates, dst_x and
+ * dst_y.
+ *
+ * This function is identical to imagecopymerge except
+ * that when merging it preserves the hue of the source by converting
+ * the destination pixels to gray scale before the copy operation.
+ *
+ * @param resource $dst_im Destination image resource.
+ * @param resource $src_im Source image resource.
+ * @param int $dst_x x-coordinate of destination point.
+ * @param int $dst_y y-coordinate of destination point.
+ * @param int $src_x x-coordinate of source point.
+ * @param int $src_y y-coordinate of source point.
+ * @param int $src_w Source width.
+ * @param int $src_h Source height.
+ * @param int $pct The src_im will be changed to grayscale according
+ * to pct where 0 is fully grayscale and 100 is
+ * unchanged. When pct = 100 this function behaves
+ * identically to imagecopy for pallete images, except for
+ * ignoring alpha components, while
+ * it implements alpha transparency for true colour images.
+ * @throws ImageException
+ *
+ */
+function imagecopymergegray($dst_im, $src_im, int $dst_x, int $dst_y, int $src_x, int $src_y, int $src_w, int $src_h, int $pct): void
+{
+ error_clear_last();
+ $result = \imagecopymergegray($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagecopyresampled copies a rectangular
+ * portion of one image to another image, smoothly interpolating pixel
+ * values so that, in particular, reducing the size of an image still
+ * retains a great deal of clarity.
+ *
+ * In other words, imagecopyresampled will take a
+ * rectangular area from src_image of width
+ * src_w and height src_h at
+ * position (src_x,src_y)
+ * and place it in a rectangular area of dst_image
+ * of width dst_w and height dst_h
+ * at position (dst_x,dst_y).
+ *
+ * If the source and destination coordinates and width and heights
+ * differ, appropriate stretching or shrinking of the image fragment
+ * will be performed. The coordinates refer to the upper left
+ * corner. This function can be used to copy regions within the
+ * same image (if dst_image is the same as
+ * src_image) but if the regions overlap the
+ * results will be unpredictable.
+ *
+ * @param resource $dst_image Destination image resource.
+ * @param resource $src_image Source image resource.
+ * @param int $dst_x x-coordinate of destination point.
+ * @param int $dst_y y-coordinate of destination point.
+ * @param int $src_x x-coordinate of source point.
+ * @param int $src_y y-coordinate of source point.
+ * @param int $dst_w Destination width.
+ * @param int $dst_h Destination height.
+ * @param int $src_w Source width.
+ * @param int $src_h Source height.
+ * @throws ImageException
+ *
+ */
+function imagecopyresampled($dst_image, $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $dst_w, int $dst_h, int $src_w, int $src_h): void
+{
+ error_clear_last();
+ $result = \imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagecopyresized copies a rectangular
+ * portion of one image to another image.
+ * dst_image is the destination image,
+ * src_image is the source image identifier.
+ *
+ * In other words, imagecopyresized will take a
+ * rectangular area from src_image of width
+ * src_w and height src_h at
+ * position (src_x,src_y)
+ * and place it in a rectangular area of dst_image
+ * of width dst_w and height dst_h
+ * at position (dst_x,dst_y).
+ *
+ * If the source and destination coordinates and width and heights
+ * differ, appropriate stretching or shrinking of the image fragment
+ * will be performed. The coordinates refer to the upper left
+ * corner. This function can be used to copy regions within the
+ * same image (if dst_image is the same as
+ * src_image) but if the regions overlap the
+ * results will be unpredictable.
+ *
+ * @param resource $dst_image Destination image resource.
+ * @param resource $src_image Source image resource.
+ * @param int $dst_x x-coordinate of destination point.
+ * @param int $dst_y y-coordinate of destination point.
+ * @param int $src_x x-coordinate of source point.
+ * @param int $src_y y-coordinate of source point.
+ * @param int $dst_w Destination width.
+ * @param int $dst_h Destination height.
+ * @param int $src_w Source width.
+ * @param int $src_h Source height.
+ * @throws ImageException
+ *
+ */
+function imagecopyresized($dst_image, $src_image, int $dst_x, int $dst_y, int $src_x, int $src_y, int $dst_w, int $dst_h, int $src_w, int $src_h): void
+{
+ error_clear_last();
+ $result = \imagecopyresized($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagecreate returns an image identifier
+ * representing a blank image of specified size.
+ *
+ * In general, we recommend the use of
+ * imagecreatetruecolor instead of
+ * imagecreate so that image processing occurs on the
+ * highest quality image possible. If you want to output a palette image, then
+ * imagetruecolortopalette should be called immediately
+ * before saving the image with imagepng or
+ * imagegif.
+ *
+ * @param int $width The image width.
+ * @param int $height The image height.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreate(int $width, int $height)
+{
+ error_clear_last();
+ $result = \imagecreate($width, $height);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagecreatefrombmp returns an image identifier
+ * representing the image obtained from the given filename.
+ *
+ * @param string $filename Path to the BMP image.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefrombmp(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefrombmp($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Create a new image from GD file or URL.
+ *
+ * @param string $filename Path to the GD file.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefromgd(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefromgd($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Create a new image from GD2 file or URL.
+ *
+ * @param string $filename Path to the GD2 image.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefromgd2(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefromgd2($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Create a new image from a given part of GD2 file or URL.
+ *
+ * @param string $filename Path to the GD2 image.
+ * @param int $srcX x-coordinate of source point.
+ * @param int $srcY y-coordinate of source point.
+ * @param int $width Source width.
+ * @param int $height Source height.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefromgd2part(string $filename, int $srcX, int $srcY, int $width, int $height)
+{
+ error_clear_last();
+ $result = \imagecreatefromgd2part($filename, $srcX, $srcY, $width, $height);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagecreatefromgif returns an image identifier
+ * representing the image obtained from the given filename.
+ *
+ * @param string $filename Path to the GIF image.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefromgif(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefromgif($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagecreatefromjpeg returns an image identifier
+ * representing the image obtained from the given filename.
+ *
+ * @param string $filename Path to the JPEG image.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefromjpeg(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefromjpeg($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagecreatefrompng returns an image identifier
+ * representing the image obtained from the given filename.
+ *
+ * @param string $filename Path to the PNG image.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefrompng(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefrompng($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagecreatefromwbmp returns an image identifier
+ * representing the image obtained from the given filename.
+ *
+ * @param string $filename Path to the WBMP image.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefromwbmp(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefromwbmp($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagecreatefromwebp returns an image identifier
+ * representing the image obtained from the given filename.
+ *
+ * @param string $filename Path to the WebP image.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefromwebp(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefromwebp($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagecreatefromxbm returns an image identifier
+ * representing the image obtained from the given filename.
+ *
+ * @param string $filename Path to the XBM image.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefromxbm(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefromxbm($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagecreatefromxpm returns an image identifier
+ * representing the image obtained from the given filename.
+ *
+ * @param string $filename Path to the XPM image.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatefromxpm(string $filename)
+{
+ error_clear_last();
+ $result = \imagecreatefromxpm($filename);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagecreatetruecolor returns an image identifier
+ * representing a black image of the specified size.
+ *
+ * @param int $width Image width.
+ * @param int $height Image height.
+ * @return resource Returns an image resource identifier on success, FALSE on errors.
+ * @throws ImageException
+ *
+ */
+function imagecreatetruecolor(int $width, int $height)
+{
+ error_clear_last();
+ $result = \imagecreatetruecolor($width, $height);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Crops an image to the given rectangular area and returns the resulting image.
+ * The given image is not modified.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param array $rect The cropping rectangle as array with keys
+ * x, y, width and
+ * height.
+ * @return resource Return cropped image resource on success.
+ * @throws ImageException
+ *
+ */
+function imagecrop($image, array $rect)
+{
+ error_clear_last();
+ $result = \imagecrop($image, $rect);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Automatically crops an image according to the given
+ * mode.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $mode One of the following constants:
+ * @param float $threshold
+ * @param int $color
+ * @return resource Returns a cropped image resource on success.
+ * If the complete image was cropped, imagecrop returns FALSE.
+ * @throws ImageException
+ *
+ */
+function imagecropauto($image, int $mode = IMG_CROP_DEFAULT, float $threshold = .5, int $color = -1)
+{
+ error_clear_last();
+ $result = \imagecropauto($image, $mode, $threshold, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * This function is deprecated. Use combination of
+ * imagesetstyle and imageline
+ * instead.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $x1 Upper left x coordinate.
+ * @param int $y1 Upper left y coordinate 0, 0 is the top left corner of the image.
+ * @param int $x2 Bottom right x coordinate.
+ * @param int $y2 Bottom right y coordinate.
+ * @param int $color The fill color. A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagedashedline($image, int $x1, int $y1, int $x2, int $y2, int $color): void
+{
+ error_clear_last();
+ $result = \imagedashedline($image, $x1, $y1, $x2, $y2, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagedestroy frees any memory associated
+ * with image image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @throws ImageException
+ *
+ */
+function imagedestroy($image): void
+{
+ error_clear_last();
+ $result = \imagedestroy($image);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Draws an ellipse centered at the specified coordinates.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $cx x-coordinate of the center.
+ * @param int $cy y-coordinate of the center.
+ * @param int $width The ellipse width.
+ * @param int $height The ellipse height.
+ * @param int $color The color of the ellipse. A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imageellipse($image, int $cx, int $cy, int $width, int $height, int $color): void
+{
+ error_clear_last();
+ $result = \imageellipse($image, $cx, $cy, $width, $height, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Performs a flood fill starting at the given coordinate (top left is 0, 0)
+ * with the given color in the
+ * image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $x x-coordinate of start point.
+ * @param int $y y-coordinate of start point.
+ * @param int $color The fill color. A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagefill($image, int $x, int $y, int $color): void
+{
+ error_clear_last();
+ $result = \imagefill($image, $x, $y, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Draws a partial arc centered at the specified coordinate in the
+ * given image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $cx x-coordinate of the center.
+ * @param int $cy y-coordinate of the center.
+ * @param int $width The arc width.
+ * @param int $height The arc height.
+ * @param int $start The arc start angle, in degrees.
+ * @param int $end The arc end angle, in degrees.
+ * 0° is located at the three-o'clock position, and the arc is drawn
+ * clockwise.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @param int $style A bitwise OR of the following possibilities:
+ *
+ * IMG_ARC_PIE
+ * IMG_ARC_CHORD
+ * IMG_ARC_NOFILL
+ * IMG_ARC_EDGED
+ *
+ * IMG_ARC_PIE and IMG_ARC_CHORD are
+ * mutually exclusive; IMG_ARC_CHORD just
+ * connects the starting and ending angles with a straight line, while
+ * IMG_ARC_PIE produces a rounded edge.
+ * IMG_ARC_NOFILL indicates that the arc
+ * or chord should be outlined, not filled. IMG_ARC_EDGED,
+ * used together with IMG_ARC_NOFILL, indicates that the
+ * beginning and ending angles should be connected to the center - this is a
+ * good way to outline (rather than fill) a 'pie slice'.
+ * @throws ImageException
+ *
+ */
+function imagefilledarc($image, int $cx, int $cy, int $width, int $height, int $start, int $end, int $color, int $style): void
+{
+ error_clear_last();
+ $result = \imagefilledarc($image, $cx, $cy, $width, $height, $start, $end, $color, $style);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Draws an ellipse centered at the specified coordinate on the given
+ * image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $cx x-coordinate of the center.
+ * @param int $cy y-coordinate of the center.
+ * @param int $width The ellipse width.
+ * @param int $height The ellipse height.
+ * @param int $color The fill color. A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagefilledellipse($image, int $cx, int $cy, int $width, int $height, int $color): void
+{
+ error_clear_last();
+ $result = \imagefilledellipse($image, $cx, $cy, $width, $height, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagefilledpolygon creates a filled polygon
+ * in the given image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param array $points An array containing the x and y
+ * coordinates of the polygons vertices consecutively.
+ * @param int $num_points Total number of points (vertices), which must be at least 3.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagefilledpolygon($image, array $points, int $num_points, int $color): void
+{
+ error_clear_last();
+ $result = \imagefilledpolygon($image, $points, $num_points, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Creates a rectangle filled with color in the given
+ * image starting at point 1 and ending at point 2.
+ * 0, 0 is the top left corner of the image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $x1 x-coordinate for point 1.
+ * @param int $y1 y-coordinate for point 1.
+ * @param int $x2 x-coordinate for point 2.
+ * @param int $y2 y-coordinate for point 2.
+ * @param int $color The fill color. A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagefilledrectangle($image, int $x1, int $y1, int $x2, int $y2, int $color): void
+{
+ error_clear_last();
+ $result = \imagefilledrectangle($image, $x1, $y1, $x2, $y2, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagefilltoborder performs a flood fill
+ * whose border color is defined by border.
+ * The starting point for the fill is x,
+ * y (top left is 0, 0) and the region is
+ * filled with color color.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $x x-coordinate of start.
+ * @param int $y y-coordinate of start.
+ * @param int $border The border color. A color identifier created with imagecolorallocate.
+ * @param int $color The fill color. A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagefilltoborder($image, int $x, int $y, int $border, int $color): void
+{
+ error_clear_last();
+ $result = \imagefilltoborder($image, $x, $y, $border, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagefilter applies the given filter
+ * filtertype on the image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $filtertype filtertype can be one of the following:
+ *
+ *
+ *
+ * IMG_FILTER_NEGATE: Reverses all colors of
+ * the image.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_GRAYSCALE: Converts the image into
+ * grayscale by changing the red, green and blue components to their
+ * weighted sum using the same coefficients as the REC.601 luma (Y')
+ * calculation. The alpha components are retained. For palette images the
+ * result may differ due to palette limitations.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_BRIGHTNESS: Changes the brightness
+ * of the image. Use arg1 to set the level of
+ * brightness. The range for the brightness is -255 to 255.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_CONTRAST: Changes the contrast of
+ * the image. Use arg1 to set the level of
+ * contrast.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_COLORIZE: Like
+ * IMG_FILTER_GRAYSCALE, except you can specify the
+ * color. Use arg1, arg2 and
+ * arg3 in the form of
+ * red, green,
+ * blue and arg4 for the
+ * alpha channel. The range for each color is 0 to 255.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_EDGEDETECT: Uses edge detection to
+ * highlight the edges in the image.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_EMBOSS: Embosses the image.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_GAUSSIAN_BLUR: Blurs the image using
+ * the Gaussian method.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_SELECTIVE_BLUR: Blurs the image.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_MEAN_REMOVAL: Uses mean removal to
+ * achieve a "sketchy" effect.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_SMOOTH: Makes the image smoother.
+ * Use arg1 to set the level of smoothness.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_PIXELATE: Applies pixelation effect
+ * to the image, use arg1 to set the block size
+ * and arg2 to set the pixelation effect mode.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_SCATTER: Applies scatter effect
+ * to the image, use arg1 and
+ * arg2 to define the effect strength and
+ * additionally arg3 to only apply the
+ * on select pixel colors.
+ *
+ *
+ *
+ * @param int $arg1
+ *
+ *
+ * IMG_FILTER_BRIGHTNESS: Brightness level.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_CONTRAST: Contrast level.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_COLORIZE: Value of red component.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_SMOOTH: Smoothness level.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_PIXELATE: Block size in pixels.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_SCATTER: Effect substraction level.
+ * This must not be higher or equal to the addition level set with
+ * arg2.
+ *
+ *
+ *
+ * @param int $arg2
+ *
+ *
+ * IMG_FILTER_COLORIZE: Value of green component.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_PIXELATE: Whether to use advanced pixelation
+ * effect or not (defaults to FALSE).
+ *
+ *
+ *
+ *
+ * IMG_FILTER_SCATTER: Effect addition level.
+ *
+ *
+ *
+ * @param int $arg3
+ *
+ *
+ * IMG_FILTER_COLORIZE: Value of blue component.
+ *
+ *
+ *
+ *
+ * IMG_FILTER_SCATTER: Optional array indexed color values
+ * to apply effect at.
+ *
+ *
+ *
+ * @param int $arg4
+ *
+ *
+ * IMG_FILTER_COLORIZE: Alpha channel, A value
+ * between 0 and 127. 0 indicates completely opaque while 127 indicates
+ * completely transparent.
+ *
+ *
+ *
+ * @throws ImageException
+ *
+ */
+function imagefilter($image, int $filtertype, int $arg1 = null, int $arg2 = null, int $arg3 = null, int $arg4 = null): void
+{
+ error_clear_last();
+ if ($arg4 !== null) {
+ $result = \imagefilter($image, $filtertype, $arg1, $arg2, $arg3, $arg4);
+ } elseif ($arg3 !== null) {
+ $result = \imagefilter($image, $filtertype, $arg1, $arg2, $arg3);
+ } elseif ($arg2 !== null) {
+ $result = \imagefilter($image, $filtertype, $arg1, $arg2);
+ } elseif ($arg1 !== null) {
+ $result = \imagefilter($image, $filtertype, $arg1);
+ } else {
+ $result = \imagefilter($image, $filtertype);
+ }
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Flips the image image using the given
+ * mode.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $mode Flip mode, this can be one of the IMG_FLIP_* constants:
+ *
+ *
+ *
+ *
+ *
+ * Constant
+ * Meaning
+ *
+ *
+ *
+ *
+ * IMG_FLIP_HORIZONTAL
+ *
+ * Flips the image horizontally.
+ *
+ *
+ *
+ * IMG_FLIP_VERTICAL
+ *
+ * Flips the image vertically.
+ *
+ *
+ *
+ * IMG_FLIP_BOTH
+ *
+ * Flips the image both horizontally and vertically.
+ *
+ *
+ *
+ *
+ *
+ * @throws ImageException
+ *
+ */
+function imageflip($image, int $mode): void
+{
+ error_clear_last();
+ $result = \imageflip($image, $mode);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Applies gamma correction to the given gd image
+ * given an input and an output gamma.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param float $inputgamma The input gamma.
+ * @param float $outputgamma The output gamma.
+ * @throws ImageException
+ *
+ */
+function imagegammacorrect($image, float $inputgamma, float $outputgamma): void
+{
+ error_clear_last();
+ $result = \imagegammacorrect($image, $inputgamma, $outputgamma);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Outputs a GD image to the given to.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param mixed $to The path or an open stream resource (which is automatically being closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be outputted directly.
+ * @throws ImageException
+ *
+ */
+function imagegd($image, $to = null): void
+{
+ error_clear_last();
+ $result = \imagegd($image, $to);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Outputs a GD2 image to the given to.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param mixed $to The path or an open stream resource (which is automatically being closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be outputted directly.
+ * @param int $chunk_size Chunk size.
+ * @param int $type Either IMG_GD2_RAW or
+ * IMG_GD2_COMPRESSED. Default is
+ * IMG_GD2_RAW.
+ * @throws ImageException
+ *
+ */
+function imagegd2($image, $to = null, int $chunk_size = 128, int $type = IMG_GD2_RAW): void
+{
+ error_clear_last();
+ $result = \imagegd2($image, $to, $chunk_size, $type);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagegif creates the GIF
+ * file in to from the image image. The
+ * image argument is the return from the
+ * imagecreate or imagecreatefrom*
+ * function.
+ *
+ * The image format will be GIF87a unless the
+ * image has been made transparent with
+ * imagecolortransparent, in which case the
+ * image format will be GIF89a.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param mixed $to The path or an open stream resource (which is automatically being closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be outputted directly.
+ * @throws ImageException
+ *
+ */
+function imagegif($image, $to = null): void
+{
+ error_clear_last();
+ $result = \imagegif($image, $to);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Grabs a screenshot of the whole screen.
+ *
+ * @return resource Returns an image resource identifier on success, FALSE on failure.
+ * @throws ImageException
+ *
+ */
+function imagegrabscreen()
+{
+ error_clear_last();
+ $result = \imagegrabscreen();
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Grabs a window or its client area using a windows handle (HWND property in COM instance)
+ *
+ * @param int $window_handle The HWND window ID.
+ * @param int $client_area Include the client area of the application window.
+ * @return resource Returns an image resource identifier on success, FALSE on failure.
+ * @throws ImageException
+ *
+ */
+function imagegrabwindow(int $window_handle, int $client_area = 0)
+{
+ error_clear_last();
+ $result = \imagegrabwindow($window_handle, $client_area);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagejpeg creates a JPEG file from
+ * the given image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param mixed $to The path or an open stream resource (which is automatically being closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be outputted directly.
+ * @param int $quality quality is optional, and ranges from 0 (worst
+ * quality, smaller file) to 100 (best quality, biggest file). The
+ * default (-1) uses the default IJG quality value (about 75).
+ * @throws ImageException
+ *
+ */
+function imagejpeg($image, $to = null, int $quality = -1): void
+{
+ error_clear_last();
+ $result = \imagejpeg($image, $to, $quality);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Set the alpha blending flag to use layering effects.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $effect One of the following constants:
+ *
+ *
+ * IMG_EFFECT_REPLACE
+ *
+ *
+ * Use pixel replacement (equivalent of passing TRUE to
+ * imagealphablending)
+ *
+ *
+ *
+ *
+ * IMG_EFFECT_ALPHABLEND
+ *
+ *
+ * Use normal pixel blending (equivalent of passing FALSE to
+ * imagealphablending)
+ *
+ *
+ *
+ *
+ * IMG_EFFECT_NORMAL
+ *
+ *
+ * Same as IMG_EFFECT_ALPHABLEND.
+ *
+ *
+ *
+ *
+ * IMG_EFFECT_OVERLAY
+ *
+ *
+ * Overlay has the effect that black background pixels will remain
+ * black, white background pixels will remain white, but grey
+ * background pixels will take the colour of the foreground pixel.
+ *
+ *
+ *
+ *
+ * IMG_EFFECT_MULTIPLY
+ *
+ *
+ * Overlays with a multiply effect.
+ *
+ *
+ *
+ *
+ * @throws ImageException
+ *
+ */
+function imagelayereffect($image, int $effect): void
+{
+ error_clear_last();
+ $result = \imagelayereffect($image, $effect);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Draws a line between the two given points.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $x1 x-coordinate for first point.
+ * @param int $y1 y-coordinate for first point.
+ * @param int $x2 x-coordinate for second point.
+ * @param int $y2 y-coordinate for second point.
+ * @param int $color The line color. A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imageline($image, int $x1, int $y1, int $x2, int $y2, int $color): void
+{
+ error_clear_last();
+ $result = \imageline($image, $x1, $y1, $x2, $y2, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imageloadfont loads a user-defined bitmap and returns
+ * its identifier.
+ *
+ * @param string $file The font file format is currently binary and architecture
+ * dependent. This means you should generate the font files on the
+ * same type of CPU as the machine you are running PHP on.
+ *
+ *
+ * Font file format
+ *
+ *
+ *
+ * byte position
+ * C data type
+ * description
+ *
+ *
+ *
+ *
+ * byte 0-3
+ * int
+ * number of characters in the font
+ *
+ *
+ * byte 4-7
+ * int
+ *
+ * value of first character in the font (often 32 for space)
+ *
+ *
+ *
+ * byte 8-11
+ * int
+ * pixel width of each character
+ *
+ *
+ * byte 12-15
+ * int
+ * pixel height of each character
+ *
+ *
+ * byte 16-
+ * char
+ *
+ * array with character data, one byte per pixel in each
+ * character, for a total of (nchars*width*height) bytes.
+ *
+ *
+ *
+ *
+ *
+ * @return int The font identifier which is always bigger than 5 to avoid conflicts with
+ * built-in fontss.
+ * @throws ImageException
+ *
+ */
+function imageloadfont(string $file): int
+{
+ error_clear_last();
+ $result = \imageloadfont($file);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imageopenpolygon draws an open polygon on the given
+ * image. Contrary to imagepolygon,
+ * no line is drawn between the last and the first point.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param array $points An array containing the polygon's vertices, e.g.:
+ *
+ *
+ *
+ *
+ * points[0]
+ * = x0
+ *
+ *
+ * points[1]
+ * = y0
+ *
+ *
+ * points[2]
+ * = x1
+ *
+ *
+ * points[3]
+ * = y1
+ *
+ *
+ *
+ *
+ * @param int $num_points Total number of points (vertices), which must be at least 3.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imageopenpolygon($image, array $points, int $num_points, int $color): void
+{
+ error_clear_last();
+ $result = \imageopenpolygon($image, $points, $num_points, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Outputs or saves a PNG image from the given
+ * image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param mixed $to The path or an open stream resource (which is automatically being closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be outputted directly.
+ *
+ * NULL is invalid if the quality and
+ * filters arguments are not used.
+ * @param int $quality Compression level: from 0 (no compression) to 9.
+ * The default (-1) uses the zlib compression default.
+ * For more information see the zlib manual.
+ * @param int $filters Allows reducing the PNG file size. It is a bitmask field which may be
+ * set to any combination of the PNG_FILTER_XXX
+ * constants. PNG_NO_FILTER or
+ * PNG_ALL_FILTERS may also be used to respectively
+ * disable or activate all filters.
+ * The default value (-1) disables filtering.
+ * @throws ImageException
+ *
+ */
+function imagepng($image, $to = null, int $quality = -1, int $filters = -1): void
+{
+ error_clear_last();
+ $result = \imagepng($image, $to, $quality, $filters);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagepolygon creates a polygon in the given
+ * image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param array $points An array containing the polygon's vertices, e.g.:
+ *
+ *
+ *
+ *
+ * points[0]
+ * = x0
+ *
+ *
+ * points[1]
+ * = y0
+ *
+ *
+ * points[2]
+ * = x1
+ *
+ *
+ * points[3]
+ * = y1
+ *
+ *
+ *
+ *
+ * @param int $num_points Total number of points (vertices), which must be at least 3.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagepolygon($image, array $points, int $num_points, int $color): void
+{
+ error_clear_last();
+ $result = \imagepolygon($image, $points, $num_points, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagerectangle creates a rectangle starting at
+ * the specified coordinates.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $x1 Upper left x coordinate.
+ * @param int $y1 Upper left y coordinate
+ * 0, 0 is the top left corner of the image.
+ * @param int $x2 Bottom right x coordinate.
+ * @param int $y2 Bottom right y coordinate.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagerectangle($image, int $x1, int $y1, int $x2, int $y2, int $color): void
+{
+ error_clear_last();
+ $result = \imagerectangle($image, $x1, $y1, $x2, $y2, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Rotates the image image using the given
+ * angle in degrees.
+ *
+ * The center of rotation is the center of the image, and the rotated
+ * image may have different dimensions than the original image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param float $angle Rotation angle, in degrees. The rotation angle is interpreted as the
+ * number of degrees to rotate the image anticlockwise.
+ * @param int $bgd_color Specifies the color of the uncovered zone after the rotation
+ * @param int $dummy This parameter is unused.
+ * @return resource Returns an image resource for the rotated image.
+ * @throws ImageException
+ *
+ */
+function imagerotate($image, float $angle, int $bgd_color, int $dummy = 0)
+{
+ error_clear_last();
+ $result = \imagerotate($image, $angle, $bgd_color, $dummy);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagesavealpha sets the flag which determines whether to retain
+ * full alpha channel information (as opposed to single-color transparency)
+ * when saving PNG images.
+ *
+ * Alphablending has to be disabled (imagealphablending($im, false))
+ * to retain the alpha-channel in the first place.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param bool $saveflag Whether to save the alpha channel or not. Defaults to FALSE.
+ * @throws ImageException
+ *
+ */
+function imagesavealpha($image, bool $saveflag): void
+{
+ error_clear_last();
+ $result = \imagesavealpha($image, $saveflag);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagescale scales an image using the given
+ * interpolation algorithm.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $new_width The width to scale the image to.
+ * @param int $new_height The height to scale the image to. If omitted or negative, the aspect
+ * ratio will be preserved.
+ * @param int $mode One of IMG_NEAREST_NEIGHBOUR,
+ * IMG_BILINEAR_FIXED,
+ * IMG_BICUBIC,
+ * IMG_BICUBIC_FIXED or anything else (will use two
+ * pass).
+ *
+ *
+ * IMG_WEIGHTED4 is not yet supported.
+ *
+ *
+ * @return resource Return the scaled image resource on success.
+ * @throws ImageException
+ *
+ */
+function imagescale($image, int $new_width, int $new_height = -1, int $mode = IMG_BILINEAR_FIXED)
+{
+ error_clear_last();
+ $result = \imagescale($image, $new_width, $new_height, $mode);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagesetbrush sets the brush image to be
+ * used by all line drawing functions (such as imageline
+ * and imagepolygon) when drawing with the special
+ * colors IMG_COLOR_BRUSHED or
+ * IMG_COLOR_STYLEDBRUSHED.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param resource $brush An image resource.
+ * @throws ImageException
+ *
+ */
+function imagesetbrush($image, $brush): void
+{
+ error_clear_last();
+ $result = \imagesetbrush($image, $brush);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagesetclip sets the current clipping rectangle, i.e.
+ * the area beyond which no pixels will be drawn.
+ *
+ * @param resource $im An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $x1 The x-coordinate of the upper left corner.
+ * @param int $y1 The y-coordinate of the upper left corner.
+ * @param int $x2 The x-coordinate of the lower right corner.
+ * @param int $y2 The y-coordinate of the lower right corner.
+ * @throws ImageException
+ *
+ */
+function imagesetclip($im, int $x1, int $y1, int $x2, int $y2): void
+{
+ error_clear_last();
+ $result = \imagesetclip($im, $x1, $y1, $x2, $y2);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Sets the interpolation method, setting an interpolation method affects the rendering
+ * of various functions in GD, such as the imagerotate function.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $method The interpolation method, which can be one of the following:
+ *
+ *
+ *
+ * IMG_BELL: Bell filter.
+ *
+ *
+ *
+ *
+ * IMG_BESSEL: Bessel filter.
+ *
+ *
+ *
+ *
+ * IMG_BICUBIC: Bicubic interpolation.
+ *
+ *
+ *
+ *
+ * IMG_BICUBIC_FIXED: Fixed point implementation of the bicubic interpolation.
+ *
+ *
+ *
+ *
+ * IMG_BILINEAR_FIXED: Fixed point implementation of the bilinear interpolation (default (also on image creation)).
+ *
+ *
+ *
+ *
+ * IMG_BLACKMAN: Blackman window function.
+ *
+ *
+ *
+ *
+ * IMG_BOX: Box blur filter.
+ *
+ *
+ *
+ *
+ * IMG_BSPLINE: Spline interpolation.
+ *
+ *
+ *
+ *
+ * IMG_CATMULLROM: Cubic Hermite spline interpolation.
+ *
+ *
+ *
+ *
+ * IMG_GAUSSIAN: Gaussian function.
+ *
+ *
+ *
+ *
+ * IMG_GENERALIZED_CUBIC: Generalized cubic spline fractal interpolation.
+ *
+ *
+ *
+ *
+ * IMG_HERMITE: Hermite interpolation.
+ *
+ *
+ *
+ *
+ * IMG_HAMMING: Hamming filter.
+ *
+ *
+ *
+ *
+ * IMG_HANNING: Hanning filter.
+ *
+ *
+ *
+ *
+ * IMG_MITCHELL: Mitchell filter.
+ *
+ *
+ *
+ *
+ * IMG_POWER: Power interpolation.
+ *
+ *
+ *
+ *
+ * IMG_QUADRATIC: Inverse quadratic interpolation.
+ *
+ *
+ *
+ *
+ * IMG_SINC: Sinc function.
+ *
+ *
+ *
+ *
+ * IMG_NEAREST_NEIGHBOUR: Nearest neighbour interpolation.
+ *
+ *
+ *
+ *
+ * IMG_WEIGHTED4: Weighting filter.
+ *
+ *
+ *
+ *
+ * IMG_TRIANGLE: Triangle interpolation.
+ *
+ *
+ *
+ * @throws ImageException
+ *
+ */
+function imagesetinterpolation($image, int $method = IMG_BILINEAR_FIXED): void
+{
+ error_clear_last();
+ $result = \imagesetinterpolation($image, $method);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagesetpixel draws a pixel at the specified
+ * coordinate.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $x x-coordinate.
+ * @param int $y y-coordinate.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagesetpixel($image, int $x, int $y, int $color): void
+{
+ error_clear_last();
+ $result = \imagesetpixel($image, $x, $y, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagesetstyle sets the style to be used by all
+ * line drawing functions (such as imageline
+ * and imagepolygon) when drawing with the special
+ * color IMG_COLOR_STYLED or lines of images with color
+ * IMG_COLOR_STYLEDBRUSHED.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param array $style An array of pixel colors. You can use the
+ * IMG_COLOR_TRANSPARENT constant to add a
+ * transparent pixel.
+ * Note that style must not be an empty array.
+ * @throws ImageException
+ *
+ */
+function imagesetstyle($image, array $style): void
+{
+ error_clear_last();
+ $result = \imagesetstyle($image, $style);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagesetthickness sets the thickness of the lines
+ * drawn when drawing rectangles, polygons, arcs etc. to
+ * thickness pixels.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $thickness Thickness, in pixels.
+ * @throws ImageException
+ *
+ */
+function imagesetthickness($image, int $thickness): void
+{
+ error_clear_last();
+ $result = \imagesetthickness($image, $thickness);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * imagesettile sets the tile image to be
+ * used by all region filling functions (such as imagefill
+ * and imagefilledpolygon) when filling with the special
+ * color IMG_COLOR_TILED.
+ *
+ * A tile is an image used to fill an area with a repeated pattern. Any
+ * GD image can be used as a tile, and by setting the transparent color index of the tile
+ * image with imagecolortransparent, a tile allows certain parts
+ * of the underlying area to shine through can be created.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param resource $tile The image resource to be used as a tile.
+ * @throws ImageException
+ *
+ */
+function imagesettile($image, $tile): void
+{
+ error_clear_last();
+ $result = \imagesettile($image, $tile);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Draws a string at the given coordinates.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $font Can be 1, 2, 3, 4, 5 for built-in
+ * fonts in latin2 encoding (where higher numbers corresponding to larger fonts) or any of your
+ * own font identifiers registered with imageloadfont.
+ * @param int $x x-coordinate of the upper left corner.
+ * @param int $y y-coordinate of the upper left corner.
+ * @param string $string The string to be written.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagestring($image, int $font, int $x, int $y, string $string, int $color): void
+{
+ error_clear_last();
+ $result = \imagestring($image, $font, $x, $y, $string, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Draws a string vertically at the given
+ * coordinates.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param int $font Can be 1, 2, 3, 4, 5 for built-in
+ * fonts in latin2 encoding (where higher numbers corresponding to larger fonts) or any of your
+ * own font identifiers registered with imageloadfont.
+ * @param int $x x-coordinate of the bottom left corner.
+ * @param int $y y-coordinate of the bottom left corner.
+ * @param string $string The string to be written.
+ * @param int $color A color identifier created with imagecolorallocate.
+ * @throws ImageException
+ *
+ */
+function imagestringup($image, int $font, int $x, int $y, string $string, int $color): void
+{
+ error_clear_last();
+ $result = \imagestringup($image, $font, $x, $y, $string, $color);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Returns the width of the given image resource.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @return int Return the width of the images.
+ * @throws ImageException
+ *
+ */
+function imagesx($image): int
+{
+ error_clear_last();
+ $result = \imagesx($image);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Returns the height of the given image resource.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @return int Return the height of the images.
+ * @throws ImageException
+ *
+ */
+function imagesy($image): int
+{
+ error_clear_last();
+ $result = \imagesy($image);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagetruecolortopalette converts a truecolor image
+ * to a palette image. The code for this function was originally drawn from
+ * the Independent JPEG Group library code, which is excellent. The code
+ * has been modified to preserve as much alpha channel information as
+ * possible in the resulting palette, in addition to preserving colors as
+ * well as possible. This does not work as well as might be hoped. It is
+ * usually best to simply produce a truecolor output image instead, which
+ * guarantees the highest output quality.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param bool $dither Indicates if the image should be dithered - if it is TRUE then
+ * dithering will be used which will result in a more speckled image but
+ * with better color approximation.
+ * @param int $ncolors Sets the maximum number of colors that should be retained in the palette.
+ * @throws ImageException
+ *
+ */
+function imagetruecolortopalette($image, bool $dither, int $ncolors): void
+{
+ error_clear_last();
+ $result = \imagetruecolortopalette($image, $dither, $ncolors);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * This function calculates and returns the bounding box in pixels
+ * for a TrueType text.
+ *
+ * @param float $size The font size in points.
+ * @param float $angle Angle in degrees in which text will be measured.
+ * @param string $fontfile The path to the TrueType font you wish to use.
+ *
+ * Depending on which version of the GD library PHP is using, when
+ * fontfile does not begin with a leading
+ * / then .ttf will be appended
+ * to the filename and the library will attempt to search for that
+ * filename along a library-defined font path.
+ *
+ * When using versions of the GD library lower than 2.0.18, a space character,
+ * rather than a semicolon, was used as the 'path separator' for different font files.
+ * Unintentional use of this feature will result in the warning message:
+ * Warning: Could not find/open font. For these affected versions, the
+ * only solution is moving the font to a path which does not contain spaces.
+ *
+ * In many cases where a font resides in the same directory as the script using it
+ * the following trick will alleviate any include problems.
+ *
+ *
+ * ]]>
+ *
+ *
+ * Note that open_basedir does
+ * not apply to fontfile.
+ * @param string $text The string to be measured.
+ * @return array imagettfbbox returns an array with 8
+ * elements representing four points making the bounding box of the
+ * text on success and FALSE on error.
+ *
+ *
+ *
+ *
+ * key
+ * contents
+ *
+ *
+ *
+ *
+ * 0
+ * lower left corner, X position
+ *
+ *
+ * 1
+ * lower left corner, Y position
+ *
+ *
+ * 2
+ * lower right corner, X position
+ *
+ *
+ * 3
+ * lower right corner, Y position
+ *
+ *
+ * 4
+ * upper right corner, X position
+ *
+ *
+ * 5
+ * upper right corner, Y position
+ *
+ *
+ * 6
+ * upper left corner, X position
+ *
+ *
+ * 7
+ * upper left corner, Y position
+ *
+ *
+ *
+ *
+ *
+ * The points are relative to the text regardless of the
+ * angle, so "upper left" means in the top left-hand
+ * corner seeing the text horizontally.
+ * @throws ImageException
+ *
+ */
+function imagettfbbox(float $size, float $angle, string $fontfile, string $text): array
+{
+ error_clear_last();
+ $result = \imagettfbbox($size, $angle, $fontfile, $text);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Writes the given text into the image using TrueType
+ * fonts.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param float $size The font size in points.
+ * @param float $angle The angle in degrees, with 0 degrees being left-to-right reading text.
+ * Higher values represent a counter-clockwise rotation. For example, a
+ * value of 90 would result in bottom-to-top reading text.
+ * @param int $x The coordinates given by x and
+ * y will define the basepoint of the first
+ * character (roughly the lower-left corner of the character). This
+ * is different from the imagestring, where
+ * x and y define the
+ * upper-left corner of the first character. For example, "top left"
+ * is 0, 0.
+ * @param int $y The y-ordinate. This sets the position of the fonts baseline, not the
+ * very bottom of the character.
+ * @param int $color The color index. Using the negative of a color index has the effect of
+ * turning off antialiasing. See imagecolorallocate.
+ * @param string $fontfile The path to the TrueType font you wish to use.
+ *
+ * Depending on which version of the GD library PHP is using, when
+ * fontfile does not begin with a leading
+ * / then .ttf will be appended
+ * to the filename and the library will attempt to search for that
+ * filename along a library-defined font path.
+ *
+ * When using versions of the GD library lower than 2.0.18, a space character,
+ * rather than a semicolon, was used as the 'path separator' for different font files.
+ * Unintentional use of this feature will result in the warning message:
+ * Warning: Could not find/open font. For these affected versions, the
+ * only solution is moving the font to a path which does not contain spaces.
+ *
+ * In many cases where a font resides in the same directory as the script using it
+ * the following trick will alleviate any include problems.
+ *
+ *
+ * ]]>
+ *
+ *
+ * Note that open_basedir does
+ * not apply to fontfile.
+ * @param string $text The text string in UTF-8 encoding.
+ *
+ * May include decimal numeric character references (of the form:
+ * €) to access characters in a font beyond position 127.
+ * The hexadecimal format (like ©) is supported.
+ * Strings in UTF-8 encoding can be passed directly.
+ *
+ * Named entities, such as ©, are not supported. Consider using
+ * html_entity_decode
+ * to decode these named entities into UTF-8 strings.
+ *
+ * If a character is used in the string which is not supported by the
+ * font, a hollow rectangle will replace the character.
+ * @return array Returns an array with 8 elements representing four points making the
+ * bounding box of the text. The order of the points is lower left, lower
+ * right, upper right, upper left. The points are relative to the text
+ * regardless of the angle, so "upper left" means in the top left-hand
+ * corner when you see the text horizontally.
+ * @throws ImageException
+ *
+ */
+function imagettftext($image, float $size, float $angle, int $x, int $y, int $color, string $fontfile, string $text): array
+{
+ error_clear_last();
+ $result = \imagettftext($image, $size, $angle, $x, $y, $color, $fontfile, $text);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * imagewbmp outputs or save a WBMP
+ * version of the given image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param mixed $to The path or an open stream resource (which is automatically being closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be outputted directly.
+ * @param int $foreground You can set the foreground color with this parameter by setting an
+ * identifier obtained from imagecolorallocate.
+ * The default foreground color is black.
+ * @throws ImageException
+ *
+ */
+function imagewbmp($image, $to = null, int $foreground = null): void
+{
+ error_clear_last();
+ if ($foreground !== null) {
+ $result = \imagewbmp($image, $to, $foreground);
+ } else {
+ $result = \imagewbmp($image, $to);
+ }
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Outputs or saves a WebP version of the given image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param mixed $to The path or an open stream resource (which is automatically being closed after this function returns) to save the file to. If not set or NULL, the raw image stream will be outputted directly.
+ * @param int $quality quality ranges from 0 (worst
+ * quality, smaller file) to 100 (best quality, biggest file).
+ * @throws ImageException
+ *
+ */
+function imagewebp($image, $to = null, int $quality = 80): void
+{
+ error_clear_last();
+ $result = \imagewebp($image, $to, $quality);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Outputs or save an XBM version of the given
+ * image.
+ *
+ * @param resource $image An image resource, returned by one of the image creation functions,
+ * such as imagecreatetruecolor.
+ * @param string|null $filename The path to save the file to, given as string. If NULL, the raw image stream will be output directly.
+ *
+ * The filename (without the .xbm extension) is also
+ * used for the C identifiers of the XBM, whereby non
+ * alphanumeric characters of the current locale are substituted by
+ * underscores. If filename is set to NULL,
+ * image is used to build the C identifiers.
+ * @param int $foreground You can set the foreground color with this parameter by setting an
+ * identifier obtained from imagecolorallocate.
+ * The default foreground color is black. All other colors are treated as
+ * background.
+ * @throws ImageException
+ *
+ */
+function imagexbm($image, ?string $filename, int $foreground = null): void
+{
+ error_clear_last();
+ if ($foreground !== null) {
+ $result = \imagexbm($image, $filename, $foreground);
+ } else {
+ $result = \imagexbm($image, $filename);
+ }
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Embeds binary IPTC data into a JPEG image.
+ *
+ * @param string $iptcdata The data to be written.
+ * @param string $jpeg_file_name Path to the JPEG image.
+ * @param int $spool Spool flag. If the spool flag is less than 2 then the JPEG will be
+ * returned as a string. Otherwise the JPEG will be printed to STDOUT.
+ * @return string|bool If spool is less than 2, the JPEG will be returned. Otherwise returns TRUE on success.
+ * @throws ImageException
+ *
+ */
+function iptcembed(string $iptcdata, string $jpeg_file_name, int $spool = 0)
+{
+ error_clear_last();
+ $result = \iptcembed($iptcdata, $jpeg_file_name, $spool);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Parses an IPTC block into its single tags.
+ *
+ * @param string $iptcblock A binary IPTC block.
+ * @return array Returns an array using the tagmarker as an index and the value as the
+ * value. It returns FALSE on error or if no IPTC data was found.
+ * @throws ImageException
+ *
+ */
+function iptcparse(string $iptcblock): array
+{
+ error_clear_last();
+ $result = \iptcparse($iptcblock);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Converts a JPEG file into a WBMP file.
+ *
+ * @param string $jpegname Path to JPEG file.
+ * @param string $wbmpname Path to destination WBMP file.
+ * @param int $dest_height Destination image height.
+ * @param int $dest_width Destination image width.
+ * @param int $threshold Threshold value, between 0 and 8 (inclusive).
+ * @throws ImageException
+ *
+ */
+function jpeg2wbmp(string $jpegname, string $wbmpname, int $dest_height, int $dest_width, int $threshold): void
+{
+ error_clear_last();
+ $result = \jpeg2wbmp($jpegname, $wbmpname, $dest_height, $dest_width, $threshold);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Converts a PNG file into a WBMP file.
+ *
+ * @param string $pngname Path to PNG file.
+ * @param string $wbmpname Path to destination WBMP file.
+ * @param int $dest_height Destination image height.
+ * @param int $dest_width Destination image width.
+ * @param int $threshold Threshold value, between 0 and 8 (inclusive).
+ * @throws ImageException
+ *
+ */
+function png2wbmp(string $pngname, string $wbmpname, int $dest_height, int $dest_width, int $threshold): void
+{
+ error_clear_last();
+ $result = \png2wbmp($pngname, $wbmpname, $dest_height, $dest_width, $threshold);
+ if ($result === false) {
+ throw ImageException::createFromPhpError();
+ }
+}
diff --git a/thecodingmachine/safe/generated/imap.php b/thecodingmachine/safe/generated/imap.php
new file mode 100644
index 000000000..acd8672c6
--- /dev/null
+++ b/thecodingmachine/safe/generated/imap.php
@@ -0,0 +1,1481 @@
+
+ *
+ *
+ * @param array $serverctrls Array of LDAP Controls to send with the request.
+ * @throws LdapException
+ *
+ */
+function ldap_add($link_identifier, string $dn, array $entry, array $serverctrls = null): void
+{
+ error_clear_last();
+ $result = \ldap_add($link_identifier, $dn, $entry, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Does the same thing as ldap_bind but returns the LDAP result resource to be parsed with ldap_parse_result.
+ *
+ * @param resource $link_identifier
+ * @param string|null $bind_rdn
+ * @param string|null $bind_password
+ * @param array $serverctrls
+ * @return resource Returns an LDAP result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_bind_ext($link_identifier, ?string $bind_rdn = null, ?string $bind_password = null, array $serverctrls = null)
+{
+ error_clear_last();
+ $result = \ldap_bind_ext($link_identifier, $bind_rdn, $bind_password, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Binds to the LDAP directory with specified RDN and password.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string|null $bind_rdn
+ * @param string|null $bind_password
+ * @throws LdapException
+ *
+ */
+function ldap_bind($link_identifier, ?string $bind_rdn = null, ?string $bind_password = null): void
+{
+ error_clear_last();
+ $result = \ldap_bind($link_identifier, $bind_rdn, $bind_password);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Retrieve the pagination information send by the server.
+ *
+ * @param resource $link An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result
+ * @param string|null $cookie An opaque structure sent by the server.
+ * @param int|null $estimated The estimated number of entries to retrieve.
+ * @throws LdapException
+ *
+ */
+function ldap_control_paged_result_response($link, $result, ?string &$cookie = null, ?int &$estimated = null): void
+{
+ error_clear_last();
+ $result = \ldap_control_paged_result_response($link, $result, $cookie, $estimated);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Enable LDAP pagination by sending the pagination control (page size, cookie...).
+ *
+ * @param resource $link An LDAP link identifier, returned by ldap_connect.
+ * @param int $pagesize The number of entries by page.
+ * @param bool $iscritical Indicates whether the pagination is critical or not.
+ * If true and if the server doesn't support pagination, the search
+ * will return no result.
+ * @param string $cookie An opaque structure sent by the server
+ * (ldap_control_paged_result_response).
+ * @throws LdapException
+ *
+ */
+function ldap_control_paged_result($link, int $pagesize, bool $iscritical = false, string $cookie = ""): void
+{
+ error_clear_last();
+ $result = \ldap_control_paged_result($link, $pagesize, $iscritical, $cookie);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Returns the number of entries stored in the result of previous search
+ * operations.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result_identifier The internal LDAP result.
+ * @return int Returns number of entries in the result.
+ * @throws LdapException
+ *
+ */
+function ldap_count_entries($link_identifier, $result_identifier): int
+{
+ error_clear_last();
+ $result = \ldap_count_entries($link_identifier, $result_identifier);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Does the same thing as ldap_delete but returns the LDAP result resource to be parsed with ldap_parse_result.
+ *
+ * @param resource $link_identifier
+ * @param string $dn
+ * @param array $serverctrls
+ * @return resource Returns an LDAP result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_delete_ext($link_identifier, string $dn, array $serverctrls = null)
+{
+ error_clear_last();
+ $result = \ldap_delete_ext($link_identifier, $dn, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Deletes a particular entry in LDAP directory.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string $dn The distinguished name of an LDAP entity.
+ * @param array $serverctrls Array of LDAP Controls to send with the request.
+ * @throws LdapException
+ *
+ */
+function ldap_delete($link_identifier, string $dn, array $serverctrls = null): void
+{
+ error_clear_last();
+ $result = \ldap_delete($link_identifier, $dn, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Performs a PASSWD extended operation.
+ *
+ * @param resource $link An LDAP link identifier, returned by ldap_connect.
+ * @param string $user dn of the user to change the password of.
+ * @param string $oldpw The old password of this user. May be ommited depending of server configuration.
+ * @param string $newpw The new password for this user. May be omitted or empty to have a generated password.
+ * @param array $serverctrls If provided, a password policy request control is send with the request and this is
+ * filled with an array of LDAP Controls
+ * returned with the request.
+ * @return mixed Returns the generated password if newpw is empty or omitted.
+ * Otherwise returns TRUE on success.
+ * @throws LdapException
+ *
+ */
+function ldap_exop_passwd($link, string $user = "", string $oldpw = "", string $newpw = "", array &$serverctrls = null)
+{
+ error_clear_last();
+ $result = \ldap_exop_passwd($link, $user, $oldpw, $newpw, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Performs a WHOAMI extended operation and returns the data.
+ *
+ * @param resource $link An LDAP link identifier, returned by ldap_connect.
+ * @return string The data returned by the server.
+ * @throws LdapException
+ *
+ */
+function ldap_exop_whoami($link): string
+{
+ error_clear_last();
+ $result = \ldap_exop_whoami($link);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Performs an extended operation on the specified link with
+ * reqoid the OID of the operation and
+ * reqdata the data.
+ *
+ * @param resource $link An LDAP link identifier, returned by ldap_connect.
+ * @param string $reqoid The extended operation request OID. You may use one of LDAP_EXOP_START_TLS, LDAP_EXOP_MODIFY_PASSWD, LDAP_EXOP_REFRESH, LDAP_EXOP_WHO_AM_I, LDAP_EXOP_TURN, or a string with the OID of the operation you want to send.
+ * @param string $reqdata The extended operation request data. May be NULL for some operations like LDAP_EXOP_WHO_AM_I, may also need to be BER encoded.
+ * @param array|null $serverctrls Array of LDAP Controls to send with the request.
+ * @param string|null $retdata Will be filled with the extended operation response data if provided.
+ * If not provided you may use ldap_parse_exop on the result object
+ * later to get this data.
+ * @param string|null $retoid Will be filled with the response OID if provided, usually equal to the request OID.
+ * @return mixed When used with retdata, returns TRUE on success.
+ * When used without retdata, returns a result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_exop($link, string $reqoid, string $reqdata = null, ?array $serverctrls = null, ?string &$retdata = null, ?string &$retoid = null)
+{
+ error_clear_last();
+ $result = \ldap_exop($link, $reqoid, $reqdata, $serverctrls, $retdata, $retoid);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Splits the DN returned by ldap_get_dn and breaks it
+ * up into its component parts. Each part is known as Relative Distinguished
+ * Name, or RDN.
+ *
+ * @param string $dn The distinguished name of an LDAP entity.
+ * @param int $with_attrib Used to request if the RDNs are returned with only values or their
+ * attributes as well. To get RDNs with the attributes (i.e. in
+ * attribute=value format) set with_attrib to 0
+ * and to get only values set it to 1.
+ * @return array Returns an array of all DN components.
+ * The first element in the array has count key and
+ * represents the number of returned values, next elements are numerically
+ * indexed DN components.
+ * @throws LdapException
+ *
+ */
+function ldap_explode_dn(string $dn, int $with_attrib): array
+{
+ error_clear_last();
+ $result = \ldap_explode_dn($dn, $with_attrib);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Gets the first attribute in the given entry. Remaining attributes are
+ * retrieved by calling ldap_next_attribute successively.
+ *
+ * Similar to reading entries, attributes are also read one by one from a
+ * particular entry.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result_entry_identifier
+ * @return string Returns the first attribute in the entry on success and FALSE on
+ * error.
+ * @throws LdapException
+ *
+ */
+function ldap_first_attribute($link_identifier, $result_entry_identifier): string
+{
+ error_clear_last();
+ $result = \ldap_first_attribute($link_identifier, $result_entry_identifier);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Returns the entry identifier for first entry in the result. This entry
+ * identifier is then supplied to ldap_next_entry
+ * routine to get successive entries from the result.
+ *
+ * Entries in the LDAP result are read sequentially using the
+ * ldap_first_entry and
+ * ldap_next_entry functions.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result_identifier
+ * @return resource Returns the result entry identifier for the first entry on success and
+ * FALSE on error.
+ * @throws LdapException
+ *
+ */
+function ldap_first_entry($link_identifier, $result_identifier)
+{
+ error_clear_last();
+ $result = \ldap_first_entry($link_identifier, $result_identifier);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Frees up the memory allocated internally to store the result. All result
+ * memory will be automatically freed when the script terminates.
+ *
+ * Typically all the memory allocated for the LDAP result gets freed at the
+ * end of the script. In case the script is making successive searches which
+ * return large result sets, ldap_free_result could be
+ * called to keep the runtime memory usage by the script low.
+ *
+ * @param resource $result_identifier
+ * @throws LdapException
+ *
+ */
+function ldap_free_result($result_identifier): void
+{
+ error_clear_last();
+ $result = \ldap_free_result($result_identifier);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Reads attributes and values from an entry in the search result.
+ *
+ * Having located a specific entry in the directory, you can find out what
+ * information is held for that entry by using this call. You would use this
+ * call for an application which "browses" directory entries and/or where you
+ * do not know the structure of the directory entries. In many applications
+ * you will be searching for a specific attribute such as an email address or
+ * a surname, and won't care what other data is held.
+ *
+ *
+ *
+ *
+ *
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result_entry_identifier
+ * @return array Returns a complete entry information in a multi-dimensional array
+ * on success and FALSE on error.
+ * @throws LdapException
+ *
+ */
+function ldap_get_attributes($link_identifier, $result_entry_identifier): array
+{
+ error_clear_last();
+ $result = \ldap_get_attributes($link_identifier, $result_entry_identifier);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Finds out the DN of an entry in the result.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result_entry_identifier
+ * @return string Returns the DN of the result entry and FALSE on error.
+ * @throws LdapException
+ *
+ */
+function ldap_get_dn($link_identifier, $result_entry_identifier): string
+{
+ error_clear_last();
+ $result = \ldap_get_dn($link_identifier, $result_entry_identifier);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Reads multiple entries from the given result, and then reading the
+ * attributes and multiple values.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result_identifier
+ * @return array Returns a complete result information in a multi-dimensional array on
+ * success and FALSE on error.
+ *
+ * The structure of the array is as follows.
+ * The attribute index is converted to lowercase. (Attributes are
+ * case-insensitive for directory servers, but not when used as
+ * array indices.)
+ *
+ *
+ *
+ *
+ *
+ * @throws LdapException
+ *
+ */
+function ldap_get_entries($link_identifier, $result_identifier): array
+{
+ error_clear_last();
+ $result = \ldap_get_entries($link_identifier, $result_identifier);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Sets retval to the value of the specified option.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param int $option The parameter option can be one of:
+ *
+ *
+ *
+ *
+ * Option
+ * Type
+ * since
+ *
+ *
+ *
+ *
+ * LDAP_OPT_DEREF
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_SIZELIMIT
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_TIMELIMIT
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_NETWORK_TIMEOUT
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_PROTOCOL_VERSION
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_ERROR_NUMBER
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_DIAGNOSTIC_MESSAGE
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_REFERRALS
+ * bool
+ *
+ *
+ *
+ * LDAP_OPT_RESTART
+ * bool
+ *
+ *
+ *
+ * LDAP_OPT_HOST_NAME
+ * string
+ *
+ *
+ *
+ * LDAP_OPT_ERROR_STRING
+ * string
+ *
+ *
+ *
+ * LDAP_OPT_MATCHED_DN
+ * string
+ *
+ *
+ *
+ * LDAP_OPT_SERVER_CONTROLS
+ * array
+ *
+ *
+ *
+ * LDAP_OPT_CLIENT_CONTROLS
+ * array
+ *
+ *
+ *
+ * LDAP_OPT_X_KEEPALIVE_IDLE
+ * int
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_KEEPALIVE_PROBES
+ * int
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_KEEPALIVE_INTERVAL
+ * int
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_CACERTDIR
+ * string
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_CACERTFILE
+ * string
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_CERTFILE
+ * string
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_CIPHER_SUITE
+ * string
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_CRLCHECK
+ * integer
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_CRL_NONE
+ * integer
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_CRL_PEER
+ * integer
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_CRL_ALL
+ * integer
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_CRLFILE
+ * string
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_DHFILE
+ * string
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_KEYILE
+ * string
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_PACKAGE
+ * string
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_PROTOCOL_MIN
+ * integer
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_RANDOM_FILE
+ * string
+ * 7.1
+ *
+ *
+ * LDAP_OPT_X_TLS_REQUIRE_CERT
+ * integer
+ *
+ *
+ *
+ *
+ *
+ * @param mixed $retval This will be set to the option value.
+ * @throws LdapException
+ *
+ */
+function ldap_get_option($link_identifier, int $option, &$retval): void
+{
+ error_clear_last();
+ $result = \ldap_get_option($link_identifier, $option, $retval);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Reads all the values of the attribute in the entry in the result.
+ *
+ * This function is used exactly like ldap_get_values
+ * except that it handles binary data and not string data.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result_entry_identifier
+ * @param string $attribute
+ * @return array Returns an array of values for the attribute on success and FALSE on
+ * error. Individual values are accessed by integer index in the array. The
+ * first index is 0. The number of values can be found by indexing "count"
+ * in the resultant array.
+ * @throws LdapException
+ *
+ */
+function ldap_get_values_len($link_identifier, $result_entry_identifier, string $attribute): array
+{
+ error_clear_last();
+ $result = \ldap_get_values_len($link_identifier, $result_entry_identifier, $attribute);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Reads all the values of the attribute in the entry in the result.
+ *
+ * This call needs a result_entry_identifier,
+ * so needs to be preceded by one of the ldap search calls and one
+ * of the calls to get an individual entry.
+ *
+ * You application will either be hard coded to look for certain
+ * attributes (such as "surname" or "mail") or you will have to use
+ * the ldap_get_attributes call to work out
+ * what attributes exist for a given entry.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result_entry_identifier
+ * @param string $attribute
+ * @return array Returns an array of values for the attribute on success and FALSE on
+ * error. The number of values can be found by indexing "count" in the
+ * resultant array. Individual values are accessed by integer index in the
+ * array. The first index is 0.
+ *
+ * LDAP allows more than one entry for an attribute, so it can, for example,
+ * store a number of email addresses for one person's directory entry all
+ * labeled with the attribute "mail"
+ *
+ *
+ * return_value["count"] = number of values for attribute
+ * return_value[0] = first value of attribute
+ * return_value[i] = ith value of attribute
+ *
+ *
+ * @throws LdapException
+ *
+ */
+function ldap_get_values($link_identifier, $result_entry_identifier, string $attribute): array
+{
+ error_clear_last();
+ $result = \ldap_get_values($link_identifier, $result_entry_identifier, $attribute);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Performs the search for a specified filter on the
+ * directory with the scope LDAP_SCOPE_ONELEVEL.
+ *
+ * LDAP_SCOPE_ONELEVEL means that the search should only
+ * return information that is at the level immediately below the
+ * base_dn given in the call.
+ * (Equivalent to typing "ls" and getting a list of files and folders in the
+ * current working directory.)
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string $base_dn The base DN for the directory.
+ * @param string $filter
+ * @param array $attributes An array of the required attributes, e.g. array("mail", "sn", "cn").
+ * Note that the "dn" is always returned irrespective of which attributes
+ * types are requested.
+ *
+ * Using this parameter is much more efficient than the default action
+ * (which is to return all attributes and their associated values).
+ * The use of this parameter should therefore be considered good
+ * practice.
+ * @param int $attrsonly Should be set to 1 if only attribute types are wanted. If set to 0
+ * both attributes types and attribute values are fetched which is the
+ * default behaviour.
+ * @param int $sizelimit Enables you to limit the count of entries fetched. Setting this to 0
+ * means no limit.
+ *
+ * This parameter can NOT override server-side preset sizelimit. You can
+ * set it lower though.
+ *
+ * Some directory server hosts will be configured to return no more than
+ * a preset number of entries. If this occurs, the server will indicate
+ * that it has only returned a partial results set. This also occurs if
+ * you use this parameter to limit the count of fetched entries.
+ * @param int $timelimit Sets the number of seconds how long is spend on the search. Setting
+ * this to 0 means no limit.
+ *
+ * This parameter can NOT override server-side preset timelimit. You can
+ * set it lower though.
+ * @param int $deref Specifies how aliases should be handled during the search. It can be
+ * one of the following:
+ *
+ *
+ *
+ * LDAP_DEREF_NEVER - (default) aliases are never
+ * dereferenced.
+ *
+ *
+ *
+ *
+ * LDAP_DEREF_SEARCHING - aliases should be
+ * dereferenced during the search but not when locating the base object
+ * of the search.
+ *
+ *
+ *
+ *
+ * LDAP_DEREF_FINDING - aliases should be
+ * dereferenced when locating the base object but not during the search.
+ *
+ *
+ *
+ *
+ * LDAP_DEREF_ALWAYS - aliases should be dereferenced
+ * always.
+ *
+ *
+ *
+ * @param array $serverctrls Array of LDAP Controls to send with the request.
+ * @return resource Returns a search result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_list($link_identifier, string $base_dn, string $filter, array $attributes = null, int $attrsonly = 0, int $sizelimit = -1, int $timelimit = -1, int $deref = LDAP_DEREF_NEVER, array $serverctrls = null)
+{
+ error_clear_last();
+ if ($serverctrls !== null) {
+ $result = \ldap_list($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref, $serverctrls);
+ } elseif ($deref !== LDAP_DEREF_NEVER) {
+ $result = \ldap_list($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref);
+ } elseif ($timelimit !== -1) {
+ $result = \ldap_list($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit, $timelimit);
+ } elseif ($sizelimit !== -1) {
+ $result = \ldap_list($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit);
+ } elseif ($attrsonly !== 0) {
+ $result = \ldap_list($link_identifier, $base_dn, $filter, $attributes, $attrsonly);
+ } elseif ($attributes !== null) {
+ $result = \ldap_list($link_identifier, $base_dn, $filter, $attributes);
+ } else {
+ $result = \ldap_list($link_identifier, $base_dn, $filter);
+ }
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Does the same thing as ldap_mod_add but returns the LDAP result resource to be parsed with ldap_parse_result.
+ *
+ * @param resource $link_identifier
+ * @param string $dn
+ * @param array $entry
+ * @param array $serverctrls
+ * @return resource Returns an LDAP result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_mod_add_ext($link_identifier, string $dn, array $entry, array $serverctrls = null)
+{
+ error_clear_last();
+ $result = \ldap_mod_add_ext($link_identifier, $dn, $entry, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Adds one or more attribute values to the specified dn.
+ * To add a whole new object see ldap_add function.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string $dn The distinguished name of an LDAP entity.
+ * @param array $entry An associative array listing the attirbute values to add. If an attribute was not existing yet it will be added. If an attribute is existing you can only add values to it if it supports multiple values.
+ * @param array $serverctrls Array of LDAP Controls to send with the request.
+ * @throws LdapException
+ *
+ */
+function ldap_mod_add($link_identifier, string $dn, array $entry, array $serverctrls = null): void
+{
+ error_clear_last();
+ $result = \ldap_mod_add($link_identifier, $dn, $entry, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Does the same thing as ldap_mod_del but returns the LDAP result resource to be parsed with ldap_parse_result.
+ *
+ * @param resource $link_identifier
+ * @param string $dn
+ * @param array $entry
+ * @param array $serverctrls
+ * @return resource Returns an LDAP result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_mod_del_ext($link_identifier, string $dn, array $entry, array $serverctrls = null)
+{
+ error_clear_last();
+ $result = \ldap_mod_del_ext($link_identifier, $dn, $entry, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Removes one or more attribute values from the specified dn.
+ * Object deletions are done by the
+ * ldap_delete function.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string $dn The distinguished name of an LDAP entity.
+ * @param array $entry
+ * @param array $serverctrls Array of LDAP Controls to send with the request.
+ * @throws LdapException
+ *
+ */
+function ldap_mod_del($link_identifier, string $dn, array $entry, array $serverctrls = null): void
+{
+ error_clear_last();
+ $result = \ldap_mod_del($link_identifier, $dn, $entry, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Does the same thing as ldap_mod_replace but returns the LDAP result resource to be parsed with ldap_parse_result.
+ *
+ * @param resource $link_identifier
+ * @param string $dn
+ * @param array $entry
+ * @param array $serverctrls
+ * @return resource Returns an LDAP result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_mod_replace_ext($link_identifier, string $dn, array $entry, array $serverctrls = null)
+{
+ error_clear_last();
+ $result = \ldap_mod_replace_ext($link_identifier, $dn, $entry, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Replaces one or more attributes from the specified dn.
+ * It may also add or remove attributes.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string $dn The distinguished name of an LDAP entity.
+ * @param array $entry An associative array listing the attributes to replace. Sending an empty array as value will remove the attribute, while sending an attribute not existing yet on this entry will add it.
+ * @param array $serverctrls Array of LDAP Controls to send with the request.
+ * @throws LdapException
+ *
+ */
+function ldap_mod_replace($link_identifier, string $dn, array $entry, array $serverctrls = null): void
+{
+ error_clear_last();
+ $result = \ldap_mod_replace($link_identifier, $dn, $entry, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Modifies an existing entry in the LDAP directory. Allows detailed
+ * specification of the modifications to perform.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string $dn The distinguished name of an LDAP entity.
+ * @param array $entry An array that specifies the modifications to make. Each entry in this
+ * array is an associative array with two or three keys:
+ * attrib maps to the name of the attribute to modify,
+ * modtype maps to the type of modification to perform,
+ * and (depending on the type of modification) values
+ * maps to an array of attribute values relevant to the modification.
+ *
+ * Possible values for modtype include:
+ *
+ *
+ * LDAP_MODIFY_BATCH_ADD
+ *
+ *
+ * Each value specified through values is added (as
+ * an additional value) to the attribute named by
+ * attrib.
+ *
+ *
+ *
+ *
+ * LDAP_MODIFY_BATCH_REMOVE
+ *
+ *
+ * Each value specified through values is removed
+ * from the attribute named by attrib. Any value of
+ * the attribute not contained in the values array
+ * will remain untouched.
+ *
+ *
+ *
+ *
+ * LDAP_MODIFY_BATCH_REMOVE_ALL
+ *
+ *
+ * All values are removed from the attribute named by
+ * attrib. A values entry must
+ * not be provided.
+ *
+ *
+ *
+ *
+ * LDAP_MODIFY_BATCH_REPLACE
+ *
+ *
+ * All current values of the attribute named by
+ * attrib are replaced with the values specified
+ * through values.
+ *
+ *
+ *
+ *
+ *
+ * Each value specified through values is added (as
+ * an additional value) to the attribute named by
+ * attrib.
+ *
+ * Each value specified through values is removed
+ * from the attribute named by attrib. Any value of
+ * the attribute not contained in the values array
+ * will remain untouched.
+ *
+ * All values are removed from the attribute named by
+ * attrib. A values entry must
+ * not be provided.
+ *
+ * All current values of the attribute named by
+ * attrib are replaced with the values specified
+ * through values.
+ *
+ * Note that any value for attrib must be a string, any
+ * value for values must be an array of strings, and
+ * any value for modtype must be one of the
+ * LDAP_MODIFY_BATCH_* constants listed above.
+ * @param array $serverctrls Each value specified through values is added (as
+ * an additional value) to the attribute named by
+ * attrib.
+ * @throws LdapException
+ *
+ */
+function ldap_modify_batch($link_identifier, string $dn, array $entry, array $serverctrls = null): void
+{
+ error_clear_last();
+ $result = \ldap_modify_batch($link_identifier, $dn, $entry, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Retrieves the attributes in an entry. The first call to
+ * ldap_next_attribute is made with the
+ * result_entry_identifier returned from
+ * ldap_first_attribute.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result_entry_identifier
+ * @return string Returns the next attribute in an entry on success and FALSE on
+ * error.
+ * @throws LdapException
+ *
+ */
+function ldap_next_attribute($link_identifier, $result_entry_identifier): string
+{
+ error_clear_last();
+ $result = \ldap_next_attribute($link_identifier, $result_entry_identifier);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Parse LDAP extended operation data from result object result
+ *
+ * @param resource $link An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result An LDAP result resource, returned by ldap_exop.
+ * @param string|null $retdata Will be filled by the response data.
+ * @param string|null $retoid Will be filled by the response OID.
+ * @throws LdapException
+ *
+ */
+function ldap_parse_exop($link, $result, ?string &$retdata = null, ?string &$retoid = null): void
+{
+ error_clear_last();
+ $result = \ldap_parse_exop($link, $result, $retdata, $retoid);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Parses an LDAP search result.
+ *
+ * @param resource $link An LDAP link identifier, returned by ldap_connect.
+ * @param resource $result An LDAP result resource, returned by ldap_list or
+ * ldap_search.
+ * @param int|null $errcode A reference to a variable that will be set to the LDAP error code in
+ * the result, or 0 if no error occurred.
+ * @param string|null $matcheddn A reference to a variable that will be set to a matched DN if one was
+ * recognised within the request, otherwise it will be set to NULL.
+ * @param string|null $errmsg A reference to a variable that will be set to the LDAP error message in
+ * the result, or an empty string if no error occurred.
+ * @param array|null $referrals A reference to a variable that will be set to an array set
+ * to all of the referral strings in the result, or an empty array if no
+ * referrals were returned.
+ * @param array|null $serverctrls An array of LDAP Controls which have been sent with the response.
+ * @throws LdapException
+ *
+ */
+function ldap_parse_result($link, $result, ?int &$errcode, ?string &$matcheddn = null, ?string &$errmsg = null, ?array &$referrals = null, ?array &$serverctrls = null): void
+{
+ error_clear_last();
+ $result = \ldap_parse_result($link, $result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Performs the search for a specified filter on the
+ * directory with the scope LDAP_SCOPE_BASE. So it is
+ * equivalent to reading an entry from the directory.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string $base_dn The base DN for the directory.
+ * @param string $filter An empty filter is not allowed. If you want to retrieve absolutely all
+ * information for this entry, use a filter of
+ * objectClass=*. If you know which entry types are
+ * used on the directory server, you might use an appropriate filter such
+ * as objectClass=inetOrgPerson.
+ * @param array $attributes An array of the required attributes, e.g. array("mail", "sn", "cn").
+ * Note that the "dn" is always returned irrespective of which attributes
+ * types are requested.
+ *
+ * Using this parameter is much more efficient than the default action
+ * (which is to return all attributes and their associated values).
+ * The use of this parameter should therefore be considered good
+ * practice.
+ * @param int $attrsonly Should be set to 1 if only attribute types are wanted. If set to 0
+ * both attributes types and attribute values are fetched which is the
+ * default behaviour.
+ * @param int $sizelimit Enables you to limit the count of entries fetched. Setting this to 0
+ * means no limit.
+ *
+ * This parameter can NOT override server-side preset sizelimit. You can
+ * set it lower though.
+ *
+ * Some directory server hosts will be configured to return no more than
+ * a preset number of entries. If this occurs, the server will indicate
+ * that it has only returned a partial results set. This also occurs if
+ * you use this parameter to limit the count of fetched entries.
+ * @param int $timelimit Sets the number of seconds how long is spend on the search. Setting
+ * this to 0 means no limit.
+ *
+ * This parameter can NOT override server-side preset timelimit. You can
+ * set it lower though.
+ * @param int $deref Specifies how aliases should be handled during the search. It can be
+ * one of the following:
+ *
+ *
+ *
+ * LDAP_DEREF_NEVER - (default) aliases are never
+ * dereferenced.
+ *
+ *
+ *
+ *
+ * LDAP_DEREF_SEARCHING - aliases should be
+ * dereferenced during the search but not when locating the base object
+ * of the search.
+ *
+ *
+ *
+ *
+ * LDAP_DEREF_FINDING - aliases should be
+ * dereferenced when locating the base object but not during the search.
+ *
+ *
+ *
+ *
+ * LDAP_DEREF_ALWAYS - aliases should be dereferenced
+ * always.
+ *
+ *
+ *
+ * @param array $serverctrls Array of LDAP Controls to send with the request.
+ * @return resource Returns a search result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_read($link_identifier, string $base_dn, string $filter, array $attributes = null, int $attrsonly = 0, int $sizelimit = -1, int $timelimit = -1, int $deref = LDAP_DEREF_NEVER, array $serverctrls = null)
+{
+ error_clear_last();
+ if ($serverctrls !== null) {
+ $result = \ldap_read($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref, $serverctrls);
+ } elseif ($deref !== LDAP_DEREF_NEVER) {
+ $result = \ldap_read($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref);
+ } elseif ($timelimit !== -1) {
+ $result = \ldap_read($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit, $timelimit);
+ } elseif ($sizelimit !== -1) {
+ $result = \ldap_read($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit);
+ } elseif ($attrsonly !== 0) {
+ $result = \ldap_read($link_identifier, $base_dn, $filter, $attributes, $attrsonly);
+ } elseif ($attributes !== null) {
+ $result = \ldap_read($link_identifier, $base_dn, $filter, $attributes);
+ } else {
+ $result = \ldap_read($link_identifier, $base_dn, $filter);
+ }
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Does the same thing as ldap_rename but returns the LDAP result resource to be parsed with ldap_parse_result.
+ *
+ * @param resource $link_identifier
+ * @param string $dn
+ * @param string $newrdn
+ * @param string $newparent
+ * @param bool $deleteoldrdn
+ * @param array $serverctrls
+ * @return resource Returns an LDAP result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_rename_ext($link_identifier, string $dn, string $newrdn, string $newparent, bool $deleteoldrdn, array $serverctrls = null)
+{
+ error_clear_last();
+ $result = \ldap_rename_ext($link_identifier, $dn, $newrdn, $newparent, $deleteoldrdn, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * The entry specified by dn is renamed/moved.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string $dn The distinguished name of an LDAP entity.
+ * @param string $newrdn The new RDN.
+ * @param string $newparent The new parent/superior entry.
+ * @param bool $deleteoldrdn If TRUE the old RDN value(s) is removed, else the old RDN value(s)
+ * is retained as non-distinguished values of the entry.
+ * @param array $serverctrls Array of LDAP Controls to send with the request.
+ * @throws LdapException
+ *
+ */
+function ldap_rename($link_identifier, string $dn, string $newrdn, string $newparent, bool $deleteoldrdn, array $serverctrls = null): void
+{
+ error_clear_last();
+ $result = \ldap_rename($link_identifier, $dn, $newrdn, $newparent, $deleteoldrdn, $serverctrls);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ *
+ *
+ * @param resource $link
+ * @param string $binddn
+ * @param string $password
+ * @param string $sasl_mech
+ * @param string $sasl_realm
+ * @param string $sasl_authc_id
+ * @param string $sasl_authz_id
+ * @param string $props
+ * @throws LdapException
+ *
+ */
+function ldap_sasl_bind($link, string $binddn = null, string $password = null, string $sasl_mech = null, string $sasl_realm = null, string $sasl_authc_id = null, string $sasl_authz_id = null, string $props = null): void
+{
+ error_clear_last();
+ $result = \ldap_sasl_bind($link, $binddn, $password, $sasl_mech, $sasl_realm, $sasl_authc_id, $sasl_authz_id, $props);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Performs the search for a specified filter on the directory with the scope
+ * of LDAP_SCOPE_SUBTREE. This is equivalent to searching
+ * the entire directory.
+ *
+ * From 4.0.5 on it's also possible to do parallel searches. To do this
+ * you use an array of link identifiers, rather than a single identifier,
+ * as the first argument. If you don't want the same base DN and the
+ * same filter for all the searches, you can also use an array of base DNs
+ * and/or an array of filters. Those arrays must be of the same size as
+ * the link identifier array since the first entries of the arrays are
+ * used for one search, the second entries are used for another, and so
+ * on. When doing parallel searches an array of search result
+ * identifiers is returned, except in case of error, then the entry
+ * corresponding to the search will be FALSE. This is very much like
+ * the value normally returned, except that a result identifier is always
+ * returned when a search was made. There are some rare cases where the
+ * normal search returns FALSE while the parallel search returns an
+ * identifier.
+ *
+ * @param resource|array $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param string $base_dn The base DN for the directory.
+ * @param string $filter The search filter can be simple or advanced, using boolean operators in
+ * the format described in the LDAP documentation (see the Netscape Directory SDK or
+ * RFC4515 for full
+ * information on filters).
+ * @param array $attributes An array of the required attributes, e.g. array("mail", "sn", "cn").
+ * Note that the "dn" is always returned irrespective of which attributes
+ * types are requested.
+ *
+ * Using this parameter is much more efficient than the default action
+ * (which is to return all attributes and their associated values).
+ * The use of this parameter should therefore be considered good
+ * practice.
+ * @param int $attrsonly Should be set to 1 if only attribute types are wanted. If set to 0
+ * both attributes types and attribute values are fetched which is the
+ * default behaviour.
+ * @param int $sizelimit Enables you to limit the count of entries fetched. Setting this to 0
+ * means no limit.
+ *
+ * This parameter can NOT override server-side preset sizelimit. You can
+ * set it lower though.
+ *
+ * Some directory server hosts will be configured to return no more than
+ * a preset number of entries. If this occurs, the server will indicate
+ * that it has only returned a partial results set. This also occurs if
+ * you use this parameter to limit the count of fetched entries.
+ * @param int $timelimit Sets the number of seconds how long is spend on the search. Setting
+ * this to 0 means no limit.
+ *
+ * This parameter can NOT override server-side preset timelimit. You can
+ * set it lower though.
+ * @param int $deref Specifies how aliases should be handled during the search. It can be
+ * one of the following:
+ *
+ *
+ *
+ * LDAP_DEREF_NEVER - (default) aliases are never
+ * dereferenced.
+ *
+ *
+ *
+ *
+ * LDAP_DEREF_SEARCHING - aliases should be
+ * dereferenced during the search but not when locating the base object
+ * of the search.
+ *
+ *
+ *
+ *
+ * LDAP_DEREF_FINDING - aliases should be
+ * dereferenced when locating the base object but not during the search.
+ *
+ *
+ *
+ *
+ * LDAP_DEREF_ALWAYS - aliases should be dereferenced
+ * always.
+ *
+ *
+ *
+ * @param array $serverctrls Array of LDAP Controls to send with the request.
+ * @return resource Returns a search result identifier.
+ * @throws LdapException
+ *
+ */
+function ldap_search($link_identifier, string $base_dn, string $filter, array $attributes = null, int $attrsonly = 0, int $sizelimit = -1, int $timelimit = -1, int $deref = LDAP_DEREF_NEVER, array $serverctrls = null)
+{
+ error_clear_last();
+ if ($serverctrls !== null) {
+ $result = \ldap_search($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref, $serverctrls);
+ } elseif ($deref !== LDAP_DEREF_NEVER) {
+ $result = \ldap_search($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit, $timelimit, $deref);
+ } elseif ($timelimit !== -1) {
+ $result = \ldap_search($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit, $timelimit);
+ } elseif ($sizelimit !== -1) {
+ $result = \ldap_search($link_identifier, $base_dn, $filter, $attributes, $attrsonly, $sizelimit);
+ } elseif ($attrsonly !== 0) {
+ $result = \ldap_search($link_identifier, $base_dn, $filter, $attributes, $attrsonly);
+ } elseif ($attributes !== null) {
+ $result = \ldap_search($link_identifier, $base_dn, $filter, $attributes);
+ } else {
+ $result = \ldap_search($link_identifier, $base_dn, $filter);
+ }
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Sets the value of the specified option to be newval.
+ *
+ * @param resource|null $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @param int $option The parameter option can be one of:
+ *
+ *
+ *
+ *
+ * Option
+ * Type
+ * Available since
+ *
+ *
+ *
+ *
+ * LDAP_OPT_DEREF
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_SIZELIMIT
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_TIMELIMIT
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_NETWORK_TIMEOUT
+ * integer
+ * PHP 5.3.0
+ *
+ *
+ * LDAP_OPT_PROTOCOL_VERSION
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_ERROR_NUMBER
+ * integer
+ *
+ *
+ *
+ * LDAP_OPT_REFERRALS
+ * bool
+ *
+ *
+ *
+ * LDAP_OPT_RESTART
+ * bool
+ *
+ *
+ *
+ * LDAP_OPT_HOST_NAME
+ * string
+ *
+ *
+ *
+ * LDAP_OPT_ERROR_STRING
+ * string
+ *
+ *
+ *
+ * LDAP_OPT_DIAGNOSTIC_MESSAGE
+ * string
+ *
+ *
+ *
+ * LDAP_OPT_MATCHED_DN
+ * string
+ *
+ *
+ *
+ * LDAP_OPT_SERVER_CONTROLS
+ * array
+ *
+ *
+ *
+ * LDAP_OPT_CLIENT_CONTROLS
+ * array
+ *
+ *
+ *
+ * LDAP_OPT_X_KEEPALIVE_IDLE
+ * int
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_KEEPALIVE_PROBES
+ * int
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_KEEPALIVE_INTERVAL
+ * int
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_CACERTDIR
+ * string
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_CACERTFILE
+ * string
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_CERTFILE
+ * string
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_CIPHER_SUITE
+ * string
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_CRLCHECK
+ * integer
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_CRLFILE
+ * string
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_DHFILE
+ * string
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_KEYFILE
+ * string
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_PROTOCOL_MIN
+ * integer
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_RANDOM_FILE
+ * string
+ * PHP 7.1.0
+ *
+ *
+ * LDAP_OPT_X_TLS_REQUIRE_CERT
+ * integer
+ * PHP 7.0.5
+ *
+ *
+ *
+ *
+ *
+ * LDAP_OPT_SERVER_CONTROLS and
+ * LDAP_OPT_CLIENT_CONTROLS require a list of
+ * controls, this means that the value must be an array of controls. A
+ * control consists of an oid identifying the control,
+ * an optional value, and an optional flag for
+ * criticality. In PHP a control is given by an
+ * array containing an element with the key oid
+ * and string value, and two optional elements. The optional
+ * elements are key value with string value
+ * and key iscritical with boolean value.
+ * iscritical defaults to FALSE
+ * if not supplied. See draft-ietf-ldapext-ldap-c-api-xx.txt
+ * for details. See also the second example below.
+ * @param mixed $newval The new value for the specified option.
+ * @throws LdapException
+ *
+ */
+function ldap_set_option($link_identifier, int $option, $newval): void
+{
+ error_clear_last();
+ $result = \ldap_set_option($link_identifier, $option, $newval);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
+
+
+/**
+ * Unbinds from the LDAP directory.
+ *
+ * @param resource $link_identifier An LDAP link identifier, returned by ldap_connect.
+ * @throws LdapException
+ *
+ */
+function ldap_unbind($link_identifier): void
+{
+ error_clear_last();
+ $result = \ldap_unbind($link_identifier);
+ if ($result === false) {
+ throw LdapException::createFromPhpError();
+ }
+}
diff --git a/thecodingmachine/safe/generated/libxml.php b/thecodingmachine/safe/generated/libxml.php
new file mode 100644
index 000000000..cef784c42
--- /dev/null
+++ b/thecodingmachine/safe/generated/libxml.php
@@ -0,0 +1,43 @@
+
+ *
+ * The above example will output:
+ *
+ * example: , this is a test
+ * example: , this is a test
+ * ]]>
+ *
+ *
+ * So, $out[0] contains array of strings that matched full pattern,
+ * and $out[1] contains array of strings enclosed by tags.
+ *
+ *
+ *
+ *
+ * If the pattern contains named subpatterns, $matches
+ * additionally contains entries for keys with the subpattern name.
+ *
+ *
+ * If the pattern contains duplicate named subpatterns, only the rightmost
+ * subpattern is stored in $matches[NAME].
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ *
+ * [1] => bar
+ * )
+ * ]]>
+ *
+ *
+ *
+ *
+ *
+ *
+ * PREG_SET_ORDER
+ *
+ *
+ * Orders results so that $matches[0] is an array of first set
+ * of matches, $matches[1] is an array of second set of matches,
+ * and so on.
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ * example: , example:
+ * this is a test, this is a test
+ * ]]>
+ *
+ *
+ *
+ *
+ *
+ *
+ * PREG_OFFSET_CAPTURE
+ *
+ *
+ * If this flag is passed, for every occurring match the appendant string
+ * offset (in bytes) will also be returned. Note that this changes the value of
+ * matches into an array of arrays where every element is an
+ * array consisting of the matched string at offset 0
+ * and its string offset into subject at offset
+ * 1.
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ * Array
+ * (
+ * [0] => Array
+ * (
+ * [0] => foobarbaz
+ * [1] => 0
+ * )
+ *
+ * )
+ *
+ * [1] => Array
+ * (
+ * [0] => Array
+ * (
+ * [0] => foo
+ * [1] => 0
+ * )
+ *
+ * )
+ *
+ * [2] => Array
+ * (
+ * [0] => Array
+ * (
+ * [0] => bar
+ * [1] => 3
+ * )
+ *
+ * )
+ *
+ * [3] => Array
+ * (
+ * [0] => Array
+ * (
+ * [0] => baz
+ * [1] => 6
+ * )
+ *
+ * )
+ *
+ * )
+ * ]]>
+ *
+ *
+ *
+ *
+ *
+ *
+ * PREG_UNMATCHED_AS_NULL
+ *
+ *
+ * If this flag is passed, unmatched subpatterns are reported as NULL;
+ * otherwise they are reported as an empty string.
+ *
+ *
+ *
+ *
+ *
+ * Orders results so that $matches[0] is an array of full
+ * pattern matches, $matches[1] is an array of strings matched by
+ * the first parenthesized subpattern, and so on.
+ *
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ * example: , this is a test
+ * example: , this is a test
+ * ]]>
+ *
+ *
+ * So, $out[0] contains array of strings that matched full pattern,
+ * and $out[1] contains array of strings enclosed by tags.
+ *
+ *
+ *
+ * The above example will output:
+ *
+ * So, $out[0] contains array of strings that matched full pattern,
+ * and $out[1] contains array of strings enclosed by tags.
+ *
+ * If the pattern contains named subpatterns, $matches
+ * additionally contains entries for keys with the subpattern name.
+ *
+ * If the pattern contains duplicate named subpatterns, only the rightmost
+ * subpattern is stored in $matches[NAME].
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ *
+ * [1] => bar
+ * )
+ * ]]>
+ *
+ *
+ *
+ * The above example will output:
+ *
+ * Orders results so that $matches[0] is an array of first set
+ * of matches, $matches[1] is an array of second set of matches,
+ * and so on.
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ * example: , example:
+ * this is a test, this is a test
+ * ]]>
+ *
+ *
+ *
+ * The above example will output:
+ *
+ * If this flag is passed, for every occurring match the appendant string
+ * offset (in bytes) will also be returned. Note that this changes the value of
+ * matches into an array of arrays where every element is an
+ * array consisting of the matched string at offset 0
+ * and its string offset into subject at offset
+ * 1.
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ * Array
+ * (
+ * [0] => Array
+ * (
+ * [0] => foobarbaz
+ * [1] => 0
+ * )
+ *
+ * )
+ *
+ * [1] => Array
+ * (
+ * [0] => Array
+ * (
+ * [0] => foo
+ * [1] => 0
+ * )
+ *
+ * )
+ *
+ * [2] => Array
+ * (
+ * [0] => Array
+ * (
+ * [0] => bar
+ * [1] => 3
+ * )
+ *
+ * )
+ *
+ * [3] => Array
+ * (
+ * [0] => Array
+ * (
+ * [0] => baz
+ * [1] => 6
+ * )
+ *
+ * )
+ *
+ * )
+ * ]]>
+ *
+ *
+ *
+ * The above example will output:
+ *
+ * If this flag is passed, unmatched subpatterns are reported as NULL;
+ * otherwise they are reported as an empty string.
+ *
+ * If no order flag is given, PREG_PATTERN_ORDER is
+ * assumed.
+ * @param int $offset Orders results so that $matches[0] is an array of full
+ * pattern matches, $matches[1] is an array of strings matched by
+ * the first parenthesized subpattern, and so on.
+ *
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ * example: , this is a test
+ * example: , this is a test
+ * ]]>
+ *
+ *
+ * So, $out[0] contains array of strings that matched full pattern,
+ * and $out[1] contains array of strings enclosed by tags.
+ *
+ *
+ *
+ * The above example will output:
+ *
+ * So, $out[0] contains array of strings that matched full pattern,
+ * and $out[1] contains array of strings enclosed by tags.
+ *
+ * If the pattern contains named subpatterns, $matches
+ * additionally contains entries for keys with the subpattern name.
+ *
+ * If the pattern contains duplicate named subpatterns, only the rightmost
+ * subpattern is stored in $matches[NAME].
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ *
+ * [1] => bar
+ * )
+ * ]]>
+ *
+ *
+ *
+ * The above example will output:
+ * @return int Returns the number of full pattern matches (which might be zero).
+ * @throws PcreException
+ *
+ */
+function preg_match_all(string $pattern, string $subject, array &$matches = null, int $flags = PREG_PATTERN_ORDER, int $offset = 0): int
+{
+ error_clear_last();
+ $result = \preg_match_all($pattern, $subject, $matches, $flags, $offset);
+ if ($result === false) {
+ throw PcreException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Searches subject for a match to the regular
+ * expression given in pattern.
+ *
+ * @param string $pattern The pattern to search for, as a string.
+ * @param string $subject The input string.
+ * @param array $matches If matches is provided, then it is filled with
+ * the results of search. $matches[0] will contain the
+ * text that matched the full pattern, $matches[1]
+ * will have the text that matched the first captured parenthesized
+ * subpattern, and so on.
+ * @param int $flags flags can be a combination of the following flags:
+ *
+ *
+ * PREG_OFFSET_CAPTURE
+ *
+ *
+ * If this flag is passed, for every occurring match the appendant string
+ * offset (in bytes) will also be returned. Note that this changes the value of
+ * matches into an array where every element is an
+ * array consisting of the matched string at offset 0
+ * and its string offset into subject at offset
+ * 1.
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ * Array
+ * (
+ * [0] => foobarbaz
+ * [1] => 0
+ * )
+ *
+ * [1] => Array
+ * (
+ * [0] => foo
+ * [1] => 0
+ * )
+ *
+ * [2] => Array
+ * (
+ * [0] => bar
+ * [1] => 3
+ * )
+ *
+ * [3] => Array
+ * (
+ * [0] => baz
+ * [1] => 6
+ * )
+ *
+ * )
+ * ]]>
+ *
+ *
+ *
+ *
+ *
+ *
+ * PREG_UNMATCHED_AS_NULL
+ *
+ *
+ * If this flag is passed, unmatched subpatterns are reported as NULL;
+ * otherwise they are reported as an empty string.
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ *
+ * string(2) "ac"
+ * [1]=>
+ * string(1) "a"
+ * [2]=>
+ * string(0) ""
+ * [3]=>
+ * string(1) "c"
+ * }
+ * array(4) {
+ * [0]=>
+ * string(2) "ac"
+ * [1]=>
+ * string(1) "a"
+ * [2]=>
+ * NULL
+ * [3]=>
+ * string(1) "c"
+ * }
+ * ]]>
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * If this flag is passed, for every occurring match the appendant string
+ * offset (in bytes) will also be returned. Note that this changes the value of
+ * matches into an array where every element is an
+ * array consisting of the matched string at offset 0
+ * and its string offset into subject at offset
+ * 1.
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ * Array
+ * (
+ * [0] => foobarbaz
+ * [1] => 0
+ * )
+ *
+ * [1] => Array
+ * (
+ * [0] => foo
+ * [1] => 0
+ * )
+ *
+ * [2] => Array
+ * (
+ * [0] => bar
+ * [1] => 3
+ * )
+ *
+ * [3] => Array
+ * (
+ * [0] => baz
+ * [1] => 6
+ * )
+ *
+ * )
+ * ]]>
+ *
+ *
+ *
+ * The above example will output:
+ *
+ * If this flag is passed, unmatched subpatterns are reported as NULL;
+ * otherwise they are reported as an empty string.
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ *
+ * string(2) "ac"
+ * [1]=>
+ * string(1) "a"
+ * [2]=>
+ * string(0) ""
+ * [3]=>
+ * string(1) "c"
+ * }
+ * array(4) {
+ * [0]=>
+ * string(2) "ac"
+ * [1]=>
+ * string(1) "a"
+ * [2]=>
+ * NULL
+ * [3]=>
+ * string(1) "c"
+ * }
+ * ]]>
+ *
+ *
+ *
+ * The above example will output:
+ * @param int $offset If this flag is passed, for every occurring match the appendant string
+ * offset (in bytes) will also be returned. Note that this changes the value of
+ * matches into an array where every element is an
+ * array consisting of the matched string at offset 0
+ * and its string offset into subject at offset
+ * 1.
+ *
+ *
+ *
+ * ]]>
+ *
+ * The above example will output:
+ *
+ * Array
+ * (
+ * [0] => foobarbaz
+ * [1] => 0
+ * )
+ *
+ * [1] => Array
+ * (
+ * [0] => foo
+ * [1] => 0
+ * )
+ *
+ * [2] => Array
+ * (
+ * [0] => bar
+ * [1] => 3
+ * )
+ *
+ * [3] => Array
+ * (
+ * [0] => baz
+ * [1] => 6
+ * )
+ *
+ * )
+ * ]]>
+ *
+ *
+ *
+ * The above example will output:
+ * @return int preg_match returns 1 if the pattern
+ * matches given subject, 0 if it does not.
+ * @throws PcreException
+ *
+ */
+function preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int
+{
+ error_clear_last();
+ $result = \preg_match($pattern, $subject, $matches, $flags, $offset);
+ if ($result === false) {
+ throw PcreException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Split the given string by a regular expression.
+ *
+ * @param string $pattern The pattern to search for, as a string.
+ * @param string $subject The input string.
+ * @param int|null $limit If specified, then only substrings up to limit
+ * are returned with the rest of the string being placed in the last
+ * substring. A limit of -1 or 0 means "no limit".
+ * @param int $flags flags can be any combination of the following
+ * flags (combined with the | bitwise operator):
+ *
+ *
+ * PREG_SPLIT_NO_EMPTY
+ *
+ *
+ * If this flag is set, only non-empty pieces will be returned by
+ * preg_split.
+ *
+ *
+ *
+ *
+ * PREG_SPLIT_DELIM_CAPTURE
+ *
+ *
+ * If this flag is set, parenthesized expression in the delimiter pattern
+ * will be captured and returned as well.
+ *
+ *
+ *
+ *
+ * PREG_SPLIT_OFFSET_CAPTURE
+ *
+ *
+ * If this flag is set, for every occurring match the appendant string
+ * offset will also be returned. Note that this changes the return
+ * value in an array where every element is an array consisting of the
+ * matched string at offset 0 and its string offset
+ * into subject at offset 1.
+ *
+ *
+ *
+ *
+ *
+ * If this flag is set, for every occurring match the appendant string
+ * offset will also be returned. Note that this changes the return
+ * value in an array where every element is an array consisting of the
+ * matched string at offset 0 and its string offset
+ * into subject at offset 1.
+ * @return array Returns an array containing substrings of subject
+ * split along boundaries matched by pattern.
+ * @throws PcreException
+ *
+ */
+function preg_split(string $pattern, string $subject, ?int $limit = -1, int $flags = 0): array
+{
+ error_clear_last();
+ $result = \preg_split($pattern, $subject, $limit, $flags);
+ if ($result === false) {
+ throw PcreException::createFromPhpError();
+ }
+ return $result;
+}
diff --git a/thecodingmachine/safe/generated/pdf.php b/thecodingmachine/safe/generated/pdf.php
new file mode 100644
index 000000000..d039b27a9
--- /dev/null
+++ b/thecodingmachine/safe/generated/pdf.php
@@ -0,0 +1,1553 @@
+
+ * ]]>
+ *
+ *
+ *
+ * @param string $prompt The prompt message.
+ * @param callable $callback The callback function takes one parameter; the
+ * user input returned.
+ * @throws ReadlineException
+ *
+ */
+function readline_callback_handler_install(string $prompt, callable $callback): void
+{
+ error_clear_last();
+ $result = \readline_callback_handler_install($prompt, $callback);
+ if ($result === false) {
+ throw ReadlineException::createFromPhpError();
+ }
+}
+
+
+/**
+ * This function clears the entire command line history.
+ *
+ * @throws ReadlineException
+ *
+ */
+function readline_clear_history(): void
+{
+ error_clear_last();
+ $result = \readline_clear_history();
+ if ($result === false) {
+ throw ReadlineException::createFromPhpError();
+ }
+}
+
+
+/**
+ * This function registers a completion function. This is the same kind of
+ * functionality you'd get if you hit your tab key while using Bash.
+ *
+ * @param callable $function You must supply the name of an existing function which accepts a
+ * partial command line and returns an array of possible matches.
+ * @throws ReadlineException
+ *
+ */
+function readline_completion_function(callable $function): void
+{
+ error_clear_last();
+ $result = \readline_completion_function($function);
+ if ($result === false) {
+ throw ReadlineException::createFromPhpError();
+ }
+}
+
+
+/**
+ * This function reads a command history from a file.
+ *
+ * @param string $filename Path to the filename containing the command history.
+ * @throws ReadlineException
+ *
+ */
+function readline_read_history(string $filename = null): void
+{
+ error_clear_last();
+ if ($filename !== null) {
+ $result = \readline_read_history($filename);
+ } else {
+ $result = \readline_read_history();
+ }
+ if ($result === false) {
+ throw ReadlineException::createFromPhpError();
+ }
+}
+
+
+/**
+ * This function writes the command history to a file.
+ *
+ * @param string $filename Path to the saved file.
+ * @throws ReadlineException
+ *
+ */
+function readline_write_history(string $filename = null): void
+{
+ error_clear_last();
+ if ($filename !== null) {
+ $result = \readline_write_history($filename);
+ } else {
+ $result = \readline_write_history();
+ }
+ if ($result === false) {
+ throw ReadlineException::createFromPhpError();
+ }
+}
diff --git a/thecodingmachine/safe/generated/rpminfo.php b/thecodingmachine/safe/generated/rpminfo.php
new file mode 100644
index 000000000..44de1ce23
--- /dev/null
+++ b/thecodingmachine/safe/generated/rpminfo.php
@@ -0,0 +1,21 @@
+
+ *
+ *
+ * @param int $length If length is given and is positive, the string
+ * returned will contain at most length characters
+ * beginning from start (depending on the length of
+ * string).
+ *
+ * If length is given and is negative, then that many
+ * characters will be omitted from the end of string
+ * (after the start position has been calculated when a
+ * start is negative). If
+ * start denotes the position of this truncation or
+ * beyond, FALSE will be returned.
+ *
+ * If length is given and is 0,
+ * FALSE or NULL, an empty string will be returned.
+ *
+ * If length is omitted, the substring starting from
+ * start until the end of the string will be
+ * returned.
+ * @return string Returns the extracted part of string;, or
+ * an empty string.
+ * @throws StringsException
+ *
+ */
+function substr(string $string, int $start, int $length = null): string
+{
+ error_clear_last();
+ if ($length !== null) {
+ $result = \substr($string, $start, $length);
+ } else {
+ $result = \substr($string, $start);
+ }
+ if ($result === false) {
+ throw StringsException::createFromPhpError();
+ }
+ return $result;
+}
+
+
+/**
+ * Operates as sprintf but accepts an array of
+ * arguments, rather than a variable number of arguments.
+ *
+ * @param string $format The format string is composed of zero or more directives:
+ * ordinary characters (excluding %) that are
+ * copied directly to the result and conversion
+ * specifications, each of which results in fetching its
+ * own parameter.
+ *
+ * A conversion specification follows this prototype:
+ * %[argnum$][flags][width][.precision]specifier.
+ *
+ * An integer followed by a dollar sign $,
+ * to specify which number argument to treat in the conversion.
+ *
+ *
+ * Flags
+ *
+ *
+ *
+ * Flag
+ * Description
+ *
+ *
+ *
+ *
+ * -
+ *
+ * Left-justify within the given field width;
+ * Right justification is the default
+ *
+ *
+ *
+ * +
+ *
+ * Prefix positive numbers with a plus sign
+ * +; Default only negative
+ * are prefixed with a negative sign.
+ *
+ *
+ *
+ * (space)
+ *
+ * Pads the result with spaces.
+ * This is the default.
+ *
+ *
+ *
+ * 0
+ *
+ * Only left-pads numbers with zeros.
+ * With s specifiers this can
+ * also right-pad with zeros.
+ *
+ *
+ *
+ * '(char)
+ *
+ * Pads the result with the character (char).
+ *
+ *
+ *
+ *
+ *
+ *
+ * An integer that says how many characters (minimum)
+ * this conversion should result in.
+ *
+ * A period . followed by an integer
+ * who's meaning depends on the specifier:
+ *
+ *
+ *
+ * For e, E,
+ * f and F
+ * specifiers: this is the number of digits to be printed
+ * after the decimal point (by default, this is 6).
+ *
+ *
+ *
+ *
+ * For g and G
+ * specifiers: this is the maximum number of significant
+ * digits to be printed.
+ *
+ *
+ *
+ *
+ * For s specifier: it acts as a cutoff point,
+ * setting a maximum character limit to the string.
+ *
+ *
+ *
+ *
+ *
+ * If the period is specified without an explicit value for precision,
+ * 0 is assumed.
+ *
+ *
+ *
+ *
+ * Specifiers
+ *
+ *
+ *
+ * Specifier
+ * Description
+ *
+ *
+ *
+ *
+ * %
+ *
+ * A literal percent character. No argument is required.
+ *
+ *
+ *
+ * b
+ *
+ * The argument is treated as an integer and presented
+ * as a binary number.
+ *
+ *
+ *
+ * c
+ *
+ * The argument is treated as an integer and presented
+ * as the character with that ASCII.
+ *
+ *
+ *
+ * d
+ *
+ * The argument is treated as an integer and presented
+ * as a (signed) decimal number.
+ *
+ *
+ *
+ * e
+ *
+ * The argument is treated as scientific notation (e.g. 1.2e+2).
+ * The precision specifier stands for the number of digits after the
+ * decimal point since PHP 5.2.1. In earlier versions, it was taken as
+ * number of significant digits (one less).
+ *
+ *
+ *
+ * E
+ *
+ * Like the e specifier but uses
+ * uppercase letter (e.g. 1.2E+2).
+ *
+ *
+ *
+ * f
+ *
+ * The argument is treated as a float and presented
+ * as a floating-point number (locale aware).
+ *
+ *
+ *
+ * F
+ *
+ * The argument is treated as a float and presented
+ * as a floating-point number (non-locale aware).
+ * Available as of PHP 5.0.3.
+ *
+ *
+ *
+ * g
+ *
+ *
+ * General format.
+ *
+ *
+ * Let P equal the precision if nonzero, 6 if the precision is omitted,
+ * or 1 if the precision is zero.
+ * Then, if a conversion with style E would have an exponent of X:
+ *
+ *
+ * If P > X ≥ −4, the conversion is with style f and precision P − (X + 1).
+ * Otherwise, the conversion is with style e and precision P − 1.
+ *
+ *
+ *
+ *
+ * G
+ *
+ * Like the g specifier but uses
+ * E and f.
+ *
+ *
+ *
+ * o
+ *
+ * The argument is treated as an integer and presented
+ * as an octal number.
+ *
+ *
+ *
+ * s
+ *
+ * The argument is treated and presented as a string.
+ *
+ *
+ *
+ * u
+ *
+ * The argument is treated as an integer and presented
+ * as an unsigned decimal number.
+ *
+ *
+ *
+ * x
+ *
+ * The argument is treated as an integer and presented
+ * as a hexadecimal number (with lowercase letters).
+ *
+ *
+ *
+ * X
+ *
+ * The argument is treated as an integer and presented
+ * as a hexadecimal number (with uppercase letters).
+ *
+ *
+ *
+ *
+ *
+ *
+ * General format.
+ *
+ * Let P equal the precision if nonzero, 6 if the precision is omitted,
+ * or 1 if the precision is zero.
+ * Then, if a conversion with style E would have an exponent of X:
+ *
+ * If P > X ≥ −4, the conversion is with style f and precision P − (X + 1).
+ * Otherwise, the conversion is with style e and precision P − 1.
+ *
+ * The c type specifier ignores padding and width
+ *
+ * Attempting to use a combination of the string and width specifiers with character sets that require more than one byte per character may result in unexpected results
+ *
+ * Variables will be co-erced to a suitable type for the specifier:
+ *
+ * Type Handling
+ *
+ *
+ *
+ * Type
+ * Specifiers
+ *
+ *
+ *
+ *
+ * string
+ * s
+ *
+ *
+ * integer
+ *
+ * d,
+ * u,
+ * c,
+ * o,
+ * x,
+ * X,
+ * b
+ *
+ *
+ *
+ * double
+ *
+ * g,
+ * G,
+ * e,
+ * E,
+ * f,
+ * F
+ *
+ *
+ *
+ *
+ *
+ * @param array $args
+ * @return string Return array values as a formatted string according to
+ * format.
+ * @throws StringsException
+ *
+ */
+function vsprintf(string $format, array $args): string
+{
+ error_clear_last();
+ $result = \vsprintf($format, $args);
+ if ($result === false) {
+ throw StringsException::createFromPhpError();
+ }
+ return $result;
+}
diff --git a/thecodingmachine/safe/generated/swoole.php b/thecodingmachine/safe/generated/swoole.php
new file mode 100644
index 000000000..334d96bd9
--- /dev/null
+++ b/thecodingmachine/safe/generated/swoole.php
@@ -0,0 +1,108 @@
+format('Y-m-d H:i:s.u'), $datetime->getTimezone());
+ }
+
+ /**
+ * @param string $format
+ * @param string $time
+ * @param DateTimeZone|null $timezone
+ * @throws DatetimeException
+ */
+ public static function createFromFormat($format, $time, $timezone = null): self
+ {
+ $datetime = parent::createFromFormat($format, $time, $timezone);
+ if ($datetime === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return self::createFromRegular($datetime);
+ }
+
+ /**
+ * @param DateTimeInterface $datetime2 The date to compare to.
+ * @param boolean $absolute [optional] Whether to return absolute difference.
+ * @return DateInterval The DateInterval object representing the difference between the two dates.
+ * @throws DatetimeException
+ */
+ public function diff($datetime2, $absolute = false): DateInterval
+ {
+ /** @var \DateInterval|false $result */
+ $result = parent::diff($datetime2, $absolute);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return $result;
+ }
+
+ /**
+ * @param string $modify A date/time string. Valid formats are explained in Date and Time Formats.
+ * @return DateTime Returns the DateTime object for method chaining.
+ * @throws DatetimeException
+ */
+ public function modify($modify): self
+ {
+ /** @var DateTime|false $result */
+ $result = parent::modify($modify);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return $result;
+ }
+
+ /**
+ * @param int $year
+ * @param int $month
+ * @param int $day
+ * @return DateTime
+ * @throws DatetimeException
+ */
+ public function setDate($year, $month, $day): self
+ {
+ /** @var DateTime|false $result */
+ $result = parent::setDate($year, $month, $day);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return $result;
+ }
+}
diff --git a/thecodingmachine/safe/lib/DateTimeImmutable.php b/thecodingmachine/safe/lib/DateTimeImmutable.php
new file mode 100644
index 000000000..114ec3a3d
--- /dev/null
+++ b/thecodingmachine/safe/lib/DateTimeImmutable.php
@@ -0,0 +1,262 @@
+innerDateTime = new parent($time, $timezone);
+ }
+
+ //switch between regular datetime and safe version
+ public static function createFromRegular(\DateTimeImmutable $datetime): self
+ {
+ $safeDatetime = new self($datetime->format('Y-m-d H:i:s.u'), $datetime->getTimezone()); //we need to also update the wrapper to not break the operators '<' and '>'
+ $safeDatetime->innerDateTime = $datetime; //to make sure we don't lose information because of the format().
+ return $safeDatetime;
+ }
+
+ //usefull if you need to switch back to regular DateTimeImmutable (for example when using DatePeriod)
+ public function getInnerDateTime(): \DateTimeImmutable
+ {
+ return $this->innerDateTime;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // overload functions with false errors
+
+ /**
+ * @param string $format
+ * @param string $time
+ * @param DateTimeZone|null $timezone
+ * @throws DatetimeException
+ */
+ public static function createFromFormat($format, $time, $timezone = null): self
+ {
+ $datetime = parent::createFromFormat($format, $time, $timezone);
+ if ($datetime === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return self::createFromRegular($datetime);
+ }
+
+ /**
+ * @param string $format
+ * @return string
+ * @throws DatetimeException
+ */
+ public function format($format): string
+ {
+ /** @var string|false $result */
+ $result = $this->innerDateTime->format($format);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return $result;
+ }
+
+ /**
+ * @param DateTimeInterface $datetime2
+ * @param bool $absolute
+ * @return DateInterval
+ * @throws DatetimeException
+ */
+ public function diff($datetime2, $absolute = false): DateInterval
+ {
+ /** @var \DateInterval|false $result */
+ $result = $this->innerDateTime->diff($datetime2, $absolute);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return $result;
+ }
+
+ /**
+ * @param string $modify
+ * @return DateTimeImmutable
+ * @throws DatetimeException
+ */
+ public function modify($modify): self
+ {
+ /** @var \DateTimeImmutable|false $result */
+ $result = $this->innerDateTime->modify($modify);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return self::createFromRegular($result); //we have to recreate a safe datetime because modify create a new instance of \DateTimeImmutable
+ }
+
+ /**
+ * @param int $year
+ * @param int $month
+ * @param int $day
+ * @return DateTimeImmutable
+ * @throws DatetimeException
+ */
+ public function setDate($year, $month, $day): self
+ {
+ /** @var \DateTimeImmutable|false $result */
+ $result = $this->innerDateTime->setDate($year, $month, $day);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return self::createFromRegular($result); //we have to recreate a safe datetime because modify create a new instance of \DateTimeImmutable
+ }
+
+ /**
+ * @param int $year
+ * @param int $week
+ * @param int $day
+ * @return DateTimeImmutable
+ * @throws DatetimeException
+ */
+ public function setISODate($year, $week, $day = 1): self
+ {
+ /** @var \DateTimeImmutable|false $result */
+ $result = $this->innerDateTime->setISODate($year, $week, $day);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return self::createFromRegular($result); //we have to recreate a safe datetime because modify create a new instance of \DateTimeImmutable
+ }
+
+ /**
+ * @param int $hour
+ * @param int $minute
+ * @param int $second
+ * @param int $microseconds
+ * @return DateTimeImmutable
+ * @throws DatetimeException
+ */
+ public function setTime($hour, $minute, $second = 0, $microseconds = 0): self
+ {
+ /** @var \DateTimeImmutable|false $result */
+ $result = $this->innerDateTime->setTime($hour, $minute, $second, $microseconds);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return self::createFromRegular($result);
+ }
+
+ /**
+ * @param int $unixtimestamp
+ * @return DateTimeImmutable
+ * @throws DatetimeException
+ */
+ public function setTimestamp($unixtimestamp): self
+ {
+ /** @var \DateTimeImmutable|false $result */
+ $result = $this->innerDateTime->setTimestamp($unixtimestamp);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return self::createFromRegular($result);
+ }
+
+ /**
+ * @param DateTimeZone $timezone
+ * @return DateTimeImmutable
+ * @throws DatetimeException
+ */
+ public function setTimezone($timezone): self
+ {
+ /** @var \DateTimeImmutable|false $result */
+ $result = $this->innerDateTime->setTimezone($timezone);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return self::createFromRegular($result);
+ }
+
+ /**
+ * @param DateInterval $interval
+ * @return DateTimeImmutable
+ * @throws DatetimeException
+ */
+ public function sub($interval): self
+ {
+ /** @var \DateTimeImmutable|false $result */
+ $result = $this->innerDateTime->sub($interval);
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return self::createFromRegular($result);
+ }
+
+ /**
+ * @throws DatetimeException
+ */
+ public function getOffset(): int
+ {
+ /** @var int|false $result */
+ $result = $this->innerDateTime->getOffset();
+ if ($result === false) {
+ throw DatetimeException::createFromPhpError();
+ }
+ return $result;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ //overload getters to use the inner datetime immutable instead of itself
+
+ /**
+ * @param DateInterval $interval
+ * @return DateTimeImmutable
+ */
+ public function add($interval): self
+ {
+ return self::createFromRegular($this->innerDateTime->add($interval));
+ }
+
+ /**
+ * @param DateTime $dateTime
+ * @return DateTimeImmutable
+ */
+ public static function createFromMutable($dateTime): self
+ {
+ return self::createFromRegular(parent::createFromMutable($dateTime));
+ }
+
+ /**
+ * @param mixed[] $array
+ * @return DateTimeImmutable
+ */
+ public static function __set_state($array): self
+ {
+ return self::createFromRegular(parent::__set_state($array));
+ }
+
+ public function getTimezone(): DateTimeZone
+ {
+ return $this->innerDateTime->getTimezone();
+ }
+
+ public function getTimestamp(): int
+ {
+ return $this->innerDateTime->getTimestamp();
+ }
+}
diff --git a/thecodingmachine/safe/lib/Exceptions/CurlException.php b/thecodingmachine/safe/lib/Exceptions/CurlException.php
new file mode 100644
index 000000000..2814066b0
--- /dev/null
+++ b/thecodingmachine/safe/lib/Exceptions/CurlException.php
@@ -0,0 +1,15 @@
+ 'PREG_INTERNAL_ERROR: Internal error',
+ PREG_BACKTRACK_LIMIT_ERROR => 'PREG_BACKTRACK_LIMIT_ERROR: Backtrack limit reached',
+ PREG_RECURSION_LIMIT_ERROR => 'PREG_RECURSION_LIMIT_ERROR: Recursion limit reached',
+ PREG_BAD_UTF8_ERROR => 'PREG_BAD_UTF8_ERROR: Invalid UTF8 character',
+ PREG_BAD_UTF8_OFFSET_ERROR => 'PREG_BAD_UTF8_OFFSET_ERROR',
+ PREG_JIT_STACKLIMIT_ERROR => 'PREG_JIT_STACKLIMIT_ERROR',
+ ];
+ $errMsg = $errorMap[preg_last_error()] ?? 'Unknown PCRE error: '.preg_last_error();
+ return new self($errMsg, \preg_last_error());
+ }
+}
diff --git a/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php b/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php
new file mode 100644
index 000000000..fbea6ad25
--- /dev/null
+++ b/thecodingmachine/safe/lib/Exceptions/SafeExceptionInterface.php
@@ -0,0 +1,9 @@
+services();
+
+ $services->set(RenameFunctionRector::class)
+ ->call('configure', [[ RenameFunctionRector::OLD_FUNCTION_TO_NEW_FUNCTION => [
+ 'apache_getenv' => 'Safe\apache_getenv',
+ 'apache_get_version' => 'Safe\apache_get_version',
+ 'apache_request_headers' => 'Safe\apache_request_headers',
+ 'apache_reset_timeout' => 'Safe\apache_reset_timeout',
+ 'apache_response_headers' => 'Safe\apache_response_headers',
+ 'apache_setenv' => 'Safe\apache_setenv',
+ 'apcu_cache_info' => 'Safe\apcu_cache_info',
+ 'apcu_cas' => 'Safe\apcu_cas',
+ 'apcu_dec' => 'Safe\apcu_dec',
+ 'apcu_fetch' => 'Safe\apcu_fetch',
+ 'apcu_inc' => 'Safe\apcu_inc',
+ 'apcu_sma_info' => 'Safe\apcu_sma_info',
+ 'apc_fetch' => 'Safe\apc_fetch',
+ 'array_combine' => 'Safe\array_combine',
+ 'array_flip' => 'Safe\array_flip',
+ 'array_replace' => 'Safe\array_replace',
+ 'array_replace_recursive' => 'Safe\array_replace_recursive',
+ 'array_walk_recursive' => 'Safe\array_walk_recursive',
+ 'arsort' => 'Safe\arsort',
+ 'asort' => 'Safe\asort',
+ 'base64_decode' => 'Safe\base64_decode',
+ 'bzclose' => 'Safe\bzclose',
+ 'bzflush' => 'Safe\bzflush',
+ 'bzread' => 'Safe\bzread',
+ 'bzwrite' => 'Safe\bzwrite',
+ 'chdir' => 'Safe\chdir',
+ 'chgrp' => 'Safe\chgrp',
+ 'chmod' => 'Safe\chmod',
+ 'chown' => 'Safe\chown',
+ 'chroot' => 'Safe\chroot',
+ 'class_alias' => 'Safe\class_alias',
+ 'class_implements' => 'Safe\class_implements',
+ 'class_parents' => 'Safe\class_parents',
+ 'class_uses' => 'Safe\class_uses',
+ 'cli_set_process_title' => 'Safe\cli_set_process_title',
+ 'closelog' => 'Safe\closelog',
+ 'com_event_sink' => 'Safe\com_event_sink',
+ 'com_load_typelib' => 'Safe\com_load_typelib',
+ 'com_print_typeinfo' => 'Safe\com_print_typeinfo',
+ 'convert_uudecode' => 'Safe\convert_uudecode',
+ 'convert_uuencode' => 'Safe\convert_uuencode',
+ 'copy' => 'Safe\copy',
+ 'create_function' => 'Safe\create_function',
+ 'cubrid_free_result' => 'Safe\cubrid_free_result',
+ 'cubrid_get_charset' => 'Safe\cubrid_get_charset',
+ 'cubrid_get_client_info' => 'Safe\cubrid_get_client_info',
+ 'cubrid_get_db_parameter' => 'Safe\cubrid_get_db_parameter',
+ 'cubrid_get_server_info' => 'Safe\cubrid_get_server_info',
+ 'cubrid_insert_id' => 'Safe\cubrid_insert_id',
+ 'cubrid_lob2_new' => 'Safe\cubrid_lob2_new',
+ 'cubrid_lob2_size' => 'Safe\cubrid_lob2_size',
+ 'cubrid_lob2_size64' => 'Safe\cubrid_lob2_size64',
+ 'cubrid_lob2_tell' => 'Safe\cubrid_lob2_tell',
+ 'cubrid_lob2_tell64' => 'Safe\cubrid_lob2_tell64',
+ 'cubrid_set_db_parameter' => 'Safe\cubrid_set_db_parameter',
+ 'curl_escape' => 'Safe\curl_escape',
+ 'curl_exec' => 'Safe\curl_exec',
+ 'curl_getinfo' => 'Safe\curl_getinfo',
+ 'curl_init' => 'Safe\curl_init',
+ 'curl_multi_errno' => 'Safe\curl_multi_errno',
+ 'curl_multi_info_read' => 'Safe\curl_multi_info_read',
+ 'curl_multi_init' => 'Safe\curl_multi_init',
+ 'curl_setopt' => 'Safe\curl_setopt',
+ 'curl_share_errno' => 'Safe\curl_share_errno',
+ 'curl_share_setopt' => 'Safe\curl_share_setopt',
+ 'curl_unescape' => 'Safe\curl_unescape',
+ 'date' => 'Safe\date',
+ 'date_parse' => 'Safe\date_parse',
+ 'date_parse_from_format' => 'Safe\date_parse_from_format',
+ 'date_sunrise' => 'Safe\date_sunrise',
+ 'date_sunset' => 'Safe\date_sunset',
+ 'date_sun_info' => 'Safe\date_sun_info',
+ 'db2_autocommit' => 'Safe\db2_autocommit',
+ 'db2_bind_param' => 'Safe\db2_bind_param',
+ 'db2_client_info' => 'Safe\db2_client_info',
+ 'db2_close' => 'Safe\db2_close',
+ 'db2_commit' => 'Safe\db2_commit',
+ 'db2_execute' => 'Safe\db2_execute',
+ 'db2_free_result' => 'Safe\db2_free_result',
+ 'db2_free_stmt' => 'Safe\db2_free_stmt',
+ 'db2_get_option' => 'Safe\db2_get_option',
+ 'db2_pclose' => 'Safe\db2_pclose',
+ 'db2_rollback' => 'Safe\db2_rollback',
+ 'db2_server_info' => 'Safe\db2_server_info',
+ 'db2_set_option' => 'Safe\db2_set_option',
+ 'define' => 'Safe\define',
+ 'deflate_add' => 'Safe\deflate_add',
+ 'deflate_init' => 'Safe\deflate_init',
+ 'disk_free_space' => 'Safe\disk_free_space',
+ 'disk_total_space' => 'Safe\disk_total_space',
+ 'dl' => 'Safe\dl',
+ 'dns_get_record' => 'Safe\dns_get_record',
+ 'eio_busy' => 'Safe\eio_busy',
+ 'eio_chmod' => 'Safe\eio_chmod',
+ 'eio_chown' => 'Safe\eio_chown',
+ 'eio_close' => 'Safe\eio_close',
+ 'eio_custom' => 'Safe\eio_custom',
+ 'eio_dup2' => 'Safe\eio_dup2',
+ 'eio_event_loop' => 'Safe\eio_event_loop',
+ 'eio_fallocate' => 'Safe\eio_fallocate',
+ 'eio_fchmod' => 'Safe\eio_fchmod',
+ 'eio_fdatasync' => 'Safe\eio_fdatasync',
+ 'eio_fstat' => 'Safe\eio_fstat',
+ 'eio_fstatvfs' => 'Safe\eio_fstatvfs',
+ 'eio_fsync' => 'Safe\eio_fsync',
+ 'eio_ftruncate' => 'Safe\eio_ftruncate',
+ 'eio_futime' => 'Safe\eio_futime',
+ 'eio_grp' => 'Safe\eio_grp',
+ 'eio_lstat' => 'Safe\eio_lstat',
+ 'eio_mkdir' => 'Safe\eio_mkdir',
+ 'eio_mknod' => 'Safe\eio_mknod',
+ 'eio_nop' => 'Safe\eio_nop',
+ 'eio_readahead' => 'Safe\eio_readahead',
+ 'eio_readdir' => 'Safe\eio_readdir',
+ 'eio_readlink' => 'Safe\eio_readlink',
+ 'eio_rename' => 'Safe\eio_rename',
+ 'eio_rmdir' => 'Safe\eio_rmdir',
+ 'eio_seek' => 'Safe\eio_seek',
+ 'eio_sendfile' => 'Safe\eio_sendfile',
+ 'eio_stat' => 'Safe\eio_stat',
+ 'eio_statvfs' => 'Safe\eio_statvfs',
+ 'eio_symlink' => 'Safe\eio_symlink',
+ 'eio_sync' => 'Safe\eio_sync',
+ 'eio_syncfs' => 'Safe\eio_syncfs',
+ 'eio_sync_file_range' => 'Safe\eio_sync_file_range',
+ 'eio_truncate' => 'Safe\eio_truncate',
+ 'eio_unlink' => 'Safe\eio_unlink',
+ 'eio_utime' => 'Safe\eio_utime',
+ 'eio_write' => 'Safe\eio_write',
+ 'error_log' => 'Safe\error_log',
+ 'fastcgi_finish_request' => 'Safe\fastcgi_finish_request',
+ 'fbird_blob_cancel' => 'Safe\fbird_blob_cancel',
+ 'fclose' => 'Safe\fclose',
+ 'fflush' => 'Safe\fflush',
+ 'file' => 'Safe\file',
+ 'fileatime' => 'Safe\fileatime',
+ 'filectime' => 'Safe\filectime',
+ 'fileinode' => 'Safe\fileinode',
+ 'filemtime' => 'Safe\filemtime',
+ 'fileowner' => 'Safe\fileowner',
+ 'filesize' => 'Safe\filesize',
+ 'file_get_contents' => 'Safe\file_get_contents',
+ 'file_put_contents' => 'Safe\file_put_contents',
+ 'filter_input_array' => 'Safe\filter_input_array',
+ 'filter_var_array' => 'Safe\filter_var_array',
+ 'finfo_close' => 'Safe\finfo_close',
+ 'finfo_open' => 'Safe\finfo_open',
+ 'flock' => 'Safe\flock',
+ 'fopen' => 'Safe\fopen',
+ 'fputcsv' => 'Safe\fputcsv',
+ 'fread' => 'Safe\fread',
+ 'fsockopen' => 'Safe\fsockopen',
+ 'ftp_alloc' => 'Safe\ftp_alloc',
+ 'ftp_append' => 'Safe\ftp_append',
+ 'ftp_cdup' => 'Safe\ftp_cdup',
+ 'ftp_chdir' => 'Safe\ftp_chdir',
+ 'ftp_chmod' => 'Safe\ftp_chmod',
+ 'ftp_close' => 'Safe\ftp_close',
+ 'ftp_connect' => 'Safe\ftp_connect',
+ 'ftp_delete' => 'Safe\ftp_delete',
+ 'ftp_fget' => 'Safe\ftp_fget',
+ 'ftp_fput' => 'Safe\ftp_fput',
+ 'ftp_get' => 'Safe\ftp_get',
+ 'ftp_login' => 'Safe\ftp_login',
+ 'ftp_mkdir' => 'Safe\ftp_mkdir',
+ 'ftp_mlsd' => 'Safe\ftp_mlsd',
+ 'ftp_nlist' => 'Safe\ftp_nlist',
+ 'ftp_pasv' => 'Safe\ftp_pasv',
+ 'ftp_put' => 'Safe\ftp_put',
+ 'ftp_pwd' => 'Safe\ftp_pwd',
+ 'ftp_rename' => 'Safe\ftp_rename',
+ 'ftp_rmdir' => 'Safe\ftp_rmdir',
+ 'ftp_site' => 'Safe\ftp_site',
+ 'ftp_ssl_connect' => 'Safe\ftp_ssl_connect',
+ 'ftp_systype' => 'Safe\ftp_systype',
+ 'ftruncate' => 'Safe\ftruncate',
+ 'fwrite' => 'Safe\fwrite',
+ 'getallheaders' => 'Safe\getallheaders',
+ 'getcwd' => 'Safe\getcwd',
+ 'gethostname' => 'Safe\gethostname',
+ 'getimagesize' => 'Safe\getimagesize',
+ 'getlastmod' => 'Safe\getlastmod',
+ 'getmygid' => 'Safe\getmygid',
+ 'getmyinode' => 'Safe\getmyinode',
+ 'getmypid' => 'Safe\getmypid',
+ 'getmyuid' => 'Safe\getmyuid',
+ 'getopt' => 'Safe\getopt',
+ 'getprotobyname' => 'Safe\getprotobyname',
+ 'getprotobynumber' => 'Safe\getprotobynumber',
+ 'get_headers' => 'Safe\get_headers',
+ 'glob' => 'Safe\glob',
+ 'gmdate' => 'Safe\gmdate',
+ 'gmp_binomial' => 'Safe\gmp_binomial',
+ 'gmp_export' => 'Safe\gmp_export',
+ 'gmp_import' => 'Safe\gmp_import',
+ 'gmp_random_seed' => 'Safe\gmp_random_seed',
+ 'gnupg_adddecryptkey' => 'Safe\gnupg_adddecryptkey',
+ 'gnupg_addencryptkey' => 'Safe\gnupg_addencryptkey',
+ 'gnupg_addsignkey' => 'Safe\gnupg_addsignkey',
+ 'gnupg_cleardecryptkeys' => 'Safe\gnupg_cleardecryptkeys',
+ 'gnupg_clearencryptkeys' => 'Safe\gnupg_clearencryptkeys',
+ 'gnupg_clearsignkeys' => 'Safe\gnupg_clearsignkeys',
+ 'gnupg_setarmor' => 'Safe\gnupg_setarmor',
+ 'gnupg_setsignmode' => 'Safe\gnupg_setsignmode',
+ 'gzclose' => 'Safe\gzclose',
+ 'gzcompress' => 'Safe\gzcompress',
+ 'gzdecode' => 'Safe\gzdecode',
+ 'gzdeflate' => 'Safe\gzdeflate',
+ 'gzencode' => 'Safe\gzencode',
+ 'gzgets' => 'Safe\gzgets',
+ 'gzgetss' => 'Safe\gzgetss',
+ 'gzinflate' => 'Safe\gzinflate',
+ 'gzpassthru' => 'Safe\gzpassthru',
+ 'gzrewind' => 'Safe\gzrewind',
+ 'gzuncompress' => 'Safe\gzuncompress',
+ 'hash_hkdf' => 'Safe\hash_hkdf',
+ 'hash_update_file' => 'Safe\hash_update_file',
+ 'header_register_callback' => 'Safe\header_register_callback',
+ 'hex2bin' => 'Safe\hex2bin',
+ 'highlight_file' => 'Safe\highlight_file',
+ 'highlight_string' => 'Safe\highlight_string',
+ 'ibase_add_user' => 'Safe\ibase_add_user',
+ 'ibase_backup' => 'Safe\ibase_backup',
+ 'ibase_blob_cancel' => 'Safe\ibase_blob_cancel',
+ 'ibase_blob_create' => 'Safe\ibase_blob_create',
+ 'ibase_blob_get' => 'Safe\ibase_blob_get',
+ 'ibase_close' => 'Safe\ibase_close',
+ 'ibase_commit' => 'Safe\ibase_commit',
+ 'ibase_commit_ret' => 'Safe\ibase_commit_ret',
+ 'ibase_connect' => 'Safe\ibase_connect',
+ 'ibase_delete_user' => 'Safe\ibase_delete_user',
+ 'ibase_drop_db' => 'Safe\ibase_drop_db',
+ 'ibase_free_event_handler' => 'Safe\ibase_free_event_handler',
+ 'ibase_free_query' => 'Safe\ibase_free_query',
+ 'ibase_free_result' => 'Safe\ibase_free_result',
+ 'ibase_maintain_db' => 'Safe\ibase_maintain_db',
+ 'ibase_modify_user' => 'Safe\ibase_modify_user',
+ 'ibase_name_result' => 'Safe\ibase_name_result',
+ 'ibase_pconnect' => 'Safe\ibase_pconnect',
+ 'ibase_restore' => 'Safe\ibase_restore',
+ 'ibase_rollback' => 'Safe\ibase_rollback',
+ 'ibase_rollback_ret' => 'Safe\ibase_rollback_ret',
+ 'ibase_service_attach' => 'Safe\ibase_service_attach',
+ 'ibase_service_detach' => 'Safe\ibase_service_detach',
+ 'iconv' => 'Safe\iconv',
+ 'iconv_get_encoding' => 'Safe\iconv_get_encoding',
+ 'iconv_set_encoding' => 'Safe\iconv_set_encoding',
+ 'image2wbmp' => 'Safe\image2wbmp',
+ 'imageaffine' => 'Safe\imageaffine',
+ 'imageaffinematrixconcat' => 'Safe\imageaffinematrixconcat',
+ 'imageaffinematrixget' => 'Safe\imageaffinematrixget',
+ 'imagealphablending' => 'Safe\imagealphablending',
+ 'imageantialias' => 'Safe\imageantialias',
+ 'imagearc' => 'Safe\imagearc',
+ 'imagebmp' => 'Safe\imagebmp',
+ 'imagechar' => 'Safe\imagechar',
+ 'imagecharup' => 'Safe\imagecharup',
+ 'imagecolorat' => 'Safe\imagecolorat',
+ 'imagecolordeallocate' => 'Safe\imagecolordeallocate',
+ 'imagecolormatch' => 'Safe\imagecolormatch',
+ 'imageconvolution' => 'Safe\imageconvolution',
+ 'imagecopy' => 'Safe\imagecopy',
+ 'imagecopymerge' => 'Safe\imagecopymerge',
+ 'imagecopymergegray' => 'Safe\imagecopymergegray',
+ 'imagecopyresampled' => 'Safe\imagecopyresampled',
+ 'imagecopyresized' => 'Safe\imagecopyresized',
+ 'imagecreate' => 'Safe\imagecreate',
+ 'imagecreatefrombmp' => 'Safe\imagecreatefrombmp',
+ 'imagecreatefromgd' => 'Safe\imagecreatefromgd',
+ 'imagecreatefromgd2' => 'Safe\imagecreatefromgd2',
+ 'imagecreatefromgd2part' => 'Safe\imagecreatefromgd2part',
+ 'imagecreatefromgif' => 'Safe\imagecreatefromgif',
+ 'imagecreatefromjpeg' => 'Safe\imagecreatefromjpeg',
+ 'imagecreatefrompng' => 'Safe\imagecreatefrompng',
+ 'imagecreatefromwbmp' => 'Safe\imagecreatefromwbmp',
+ 'imagecreatefromwebp' => 'Safe\imagecreatefromwebp',
+ 'imagecreatefromxbm' => 'Safe\imagecreatefromxbm',
+ 'imagecreatefromxpm' => 'Safe\imagecreatefromxpm',
+ 'imagecreatetruecolor' => 'Safe\imagecreatetruecolor',
+ 'imagecrop' => 'Safe\imagecrop',
+ 'imagecropauto' => 'Safe\imagecropauto',
+ 'imagedashedline' => 'Safe\imagedashedline',
+ 'imagedestroy' => 'Safe\imagedestroy',
+ 'imageellipse' => 'Safe\imageellipse',
+ 'imagefill' => 'Safe\imagefill',
+ 'imagefilledarc' => 'Safe\imagefilledarc',
+ 'imagefilledellipse' => 'Safe\imagefilledellipse',
+ 'imagefilledpolygon' => 'Safe\imagefilledpolygon',
+ 'imagefilledrectangle' => 'Safe\imagefilledrectangle',
+ 'imagefilltoborder' => 'Safe\imagefilltoborder',
+ 'imagefilter' => 'Safe\imagefilter',
+ 'imageflip' => 'Safe\imageflip',
+ 'imagegammacorrect' => 'Safe\imagegammacorrect',
+ 'imagegd' => 'Safe\imagegd',
+ 'imagegd2' => 'Safe\imagegd2',
+ 'imagegif' => 'Safe\imagegif',
+ 'imagegrabscreen' => 'Safe\imagegrabscreen',
+ 'imagegrabwindow' => 'Safe\imagegrabwindow',
+ 'imagejpeg' => 'Safe\imagejpeg',
+ 'imagelayereffect' => 'Safe\imagelayereffect',
+ 'imageline' => 'Safe\imageline',
+ 'imageloadfont' => 'Safe\imageloadfont',
+ 'imageopenpolygon' => 'Safe\imageopenpolygon',
+ 'imagepng' => 'Safe\imagepng',
+ 'imagepolygon' => 'Safe\imagepolygon',
+ 'imagerectangle' => 'Safe\imagerectangle',
+ 'imagerotate' => 'Safe\imagerotate',
+ 'imagesavealpha' => 'Safe\imagesavealpha',
+ 'imagescale' => 'Safe\imagescale',
+ 'imagesetbrush' => 'Safe\imagesetbrush',
+ 'imagesetclip' => 'Safe\imagesetclip',
+ 'imagesetinterpolation' => 'Safe\imagesetinterpolation',
+ 'imagesetpixel' => 'Safe\imagesetpixel',
+ 'imagesetstyle' => 'Safe\imagesetstyle',
+ 'imagesetthickness' => 'Safe\imagesetthickness',
+ 'imagesettile' => 'Safe\imagesettile',
+ 'imagestring' => 'Safe\imagestring',
+ 'imagestringup' => 'Safe\imagestringup',
+ 'imagesx' => 'Safe\imagesx',
+ 'imagesy' => 'Safe\imagesy',
+ 'imagetruecolortopalette' => 'Safe\imagetruecolortopalette',
+ 'imagettfbbox' => 'Safe\imagettfbbox',
+ 'imagettftext' => 'Safe\imagettftext',
+ 'imagewbmp' => 'Safe\imagewbmp',
+ 'imagewebp' => 'Safe\imagewebp',
+ 'imagexbm' => 'Safe\imagexbm',
+ 'imap_append' => 'Safe\imap_append',
+ 'imap_check' => 'Safe\imap_check',
+ 'imap_clearflag_full' => 'Safe\imap_clearflag_full',
+ 'imap_close' => 'Safe\imap_close',
+ 'imap_createmailbox' => 'Safe\imap_createmailbox',
+ 'imap_deletemailbox' => 'Safe\imap_deletemailbox',
+ 'imap_fetchstructure' => 'Safe\imap_fetchstructure',
+ 'imap_gc' => 'Safe\imap_gc',
+ 'imap_headerinfo' => 'Safe\imap_headerinfo',
+ 'imap_mail' => 'Safe\imap_mail',
+ 'imap_mailboxmsginfo' => 'Safe\imap_mailboxmsginfo',
+ 'imap_mail_compose' => 'Safe\imap_mail_compose',
+ 'imap_mail_copy' => 'Safe\imap_mail_copy',
+ 'imap_mail_move' => 'Safe\imap_mail_move',
+ 'imap_mutf7_to_utf8' => 'Safe\imap_mutf7_to_utf8',
+ 'imap_num_msg' => 'Safe\imap_num_msg',
+ 'imap_open' => 'Safe\imap_open',
+ 'imap_renamemailbox' => 'Safe\imap_renamemailbox',
+ 'imap_savebody' => 'Safe\imap_savebody',
+ 'imap_setacl' => 'Safe\imap_setacl',
+ 'imap_setflag_full' => 'Safe\imap_setflag_full',
+ 'imap_set_quota' => 'Safe\imap_set_quota',
+ 'imap_sort' => 'Safe\imap_sort',
+ 'imap_subscribe' => 'Safe\imap_subscribe',
+ 'imap_thread' => 'Safe\imap_thread',
+ 'imap_timeout' => 'Safe\imap_timeout',
+ 'imap_undelete' => 'Safe\imap_undelete',
+ 'imap_unsubscribe' => 'Safe\imap_unsubscribe',
+ 'imap_utf8_to_mutf7' => 'Safe\imap_utf8_to_mutf7',
+ 'inet_ntop' => 'Safe\inet_ntop',
+ 'inflate_add' => 'Safe\inflate_add',
+ 'inflate_get_read_len' => 'Safe\inflate_get_read_len',
+ 'inflate_get_status' => 'Safe\inflate_get_status',
+ 'inflate_init' => 'Safe\inflate_init',
+ 'ingres_autocommit' => 'Safe\ingres_autocommit',
+ 'ingres_close' => 'Safe\ingres_close',
+ 'ingres_commit' => 'Safe\ingres_commit',
+ 'ingres_connect' => 'Safe\ingres_connect',
+ 'ingres_execute' => 'Safe\ingres_execute',
+ 'ingres_field_name' => 'Safe\ingres_field_name',
+ 'ingres_field_type' => 'Safe\ingres_field_type',
+ 'ingres_free_result' => 'Safe\ingres_free_result',
+ 'ingres_pconnect' => 'Safe\ingres_pconnect',
+ 'ingres_result_seek' => 'Safe\ingres_result_seek',
+ 'ingres_rollback' => 'Safe\ingres_rollback',
+ 'ingres_set_environment' => 'Safe\ingres_set_environment',
+ 'ini_get' => 'Safe\ini_get',
+ 'ini_set' => 'Safe\ini_set',
+ 'inotify_init' => 'Safe\inotify_init',
+ 'inotify_rm_watch' => 'Safe\inotify_rm_watch',
+ 'iptcembed' => 'Safe\iptcembed',
+ 'iptcparse' => 'Safe\iptcparse',
+ 'jdtounix' => 'Safe\jdtounix',
+ 'jpeg2wbmp' => 'Safe\jpeg2wbmp',
+ 'json_decode' => 'Safe\json_decode',
+ 'json_encode' => 'Safe\json_encode',
+ 'json_last_error_msg' => 'Safe\json_last_error_msg',
+ 'krsort' => 'Safe\krsort',
+ 'ksort' => 'Safe\ksort',
+ 'lchgrp' => 'Safe\lchgrp',
+ 'lchown' => 'Safe\lchown',
+ 'ldap_add' => 'Safe\ldap_add',
+ 'ldap_add_ext' => 'Safe\ldap_add_ext',
+ 'ldap_bind' => 'Safe\ldap_bind',
+ 'ldap_bind_ext' => 'Safe\ldap_bind_ext',
+ 'ldap_control_paged_result' => 'Safe\ldap_control_paged_result',
+ 'ldap_control_paged_result_response' => 'Safe\ldap_control_paged_result_response',
+ 'ldap_count_entries' => 'Safe\ldap_count_entries',
+ 'ldap_delete' => 'Safe\ldap_delete',
+ 'ldap_delete_ext' => 'Safe\ldap_delete_ext',
+ 'ldap_exop' => 'Safe\ldap_exop',
+ 'ldap_exop_passwd' => 'Safe\ldap_exop_passwd',
+ 'ldap_exop_whoami' => 'Safe\ldap_exop_whoami',
+ 'ldap_explode_dn' => 'Safe\ldap_explode_dn',
+ 'ldap_first_attribute' => 'Safe\ldap_first_attribute',
+ 'ldap_first_entry' => 'Safe\ldap_first_entry',
+ 'ldap_free_result' => 'Safe\ldap_free_result',
+ 'ldap_get_attributes' => 'Safe\ldap_get_attributes',
+ 'ldap_get_dn' => 'Safe\ldap_get_dn',
+ 'ldap_get_entries' => 'Safe\ldap_get_entries',
+ 'ldap_get_option' => 'Safe\ldap_get_option',
+ 'ldap_get_values' => 'Safe\ldap_get_values',
+ 'ldap_get_values_len' => 'Safe\ldap_get_values_len',
+ 'ldap_list' => 'Safe\ldap_list',
+ 'ldap_modify_batch' => 'Safe\ldap_modify_batch',
+ 'ldap_mod_add' => 'Safe\ldap_mod_add',
+ 'ldap_mod_add_ext' => 'Safe\ldap_mod_add_ext',
+ 'ldap_mod_del' => 'Safe\ldap_mod_del',
+ 'ldap_mod_del_ext' => 'Safe\ldap_mod_del_ext',
+ 'ldap_mod_replace' => 'Safe\ldap_mod_replace',
+ 'ldap_mod_replace_ext' => 'Safe\ldap_mod_replace_ext',
+ 'ldap_next_attribute' => 'Safe\ldap_next_attribute',
+ 'ldap_parse_exop' => 'Safe\ldap_parse_exop',
+ 'ldap_parse_result' => 'Safe\ldap_parse_result',
+ 'ldap_read' => 'Safe\ldap_read',
+ 'ldap_rename' => 'Safe\ldap_rename',
+ 'ldap_rename_ext' => 'Safe\ldap_rename_ext',
+ 'ldap_sasl_bind' => 'Safe\ldap_sasl_bind',
+ 'ldap_search' => 'Safe\ldap_search',
+ 'ldap_set_option' => 'Safe\ldap_set_option',
+ 'ldap_unbind' => 'Safe\ldap_unbind',
+ 'libxml_get_last_error' => 'Safe\libxml_get_last_error',
+ 'libxml_set_external_entity_loader' => 'Safe\libxml_set_external_entity_loader',
+ 'link' => 'Safe\link',
+ 'lzf_compress' => 'Safe\lzf_compress',
+ 'lzf_decompress' => 'Safe\lzf_decompress',
+ 'mailparse_msg_extract_part_file' => 'Safe\mailparse_msg_extract_part_file',
+ 'mailparse_msg_free' => 'Safe\mailparse_msg_free',
+ 'mailparse_msg_parse' => 'Safe\mailparse_msg_parse',
+ 'mailparse_msg_parse_file' => 'Safe\mailparse_msg_parse_file',
+ 'mailparse_stream_encode' => 'Safe\mailparse_stream_encode',
+ 'mb_chr' => 'Safe\mb_chr',
+ 'mb_detect_order' => 'Safe\mb_detect_order',
+ 'mb_encoding_aliases' => 'Safe\mb_encoding_aliases',
+ 'mb_eregi_replace' => 'Safe\mb_eregi_replace',
+ 'mb_ereg_replace' => 'Safe\mb_ereg_replace',
+ 'mb_ereg_replace_callback' => 'Safe\mb_ereg_replace_callback',
+ 'mb_ereg_search_getregs' => 'Safe\mb_ereg_search_getregs',
+ 'mb_ereg_search_init' => 'Safe\mb_ereg_search_init',
+ 'mb_ereg_search_regs' => 'Safe\mb_ereg_search_regs',
+ 'mb_ereg_search_setpos' => 'Safe\mb_ereg_search_setpos',
+ 'mb_http_output' => 'Safe\mb_http_output',
+ 'mb_internal_encoding' => 'Safe\mb_internal_encoding',
+ 'mb_ord' => 'Safe\mb_ord',
+ 'mb_parse_str' => 'Safe\mb_parse_str',
+ 'mb_regex_encoding' => 'Safe\mb_regex_encoding',
+ 'mb_send_mail' => 'Safe\mb_send_mail',
+ 'mb_split' => 'Safe\mb_split',
+ 'mb_str_split' => 'Safe\mb_str_split',
+ 'md5_file' => 'Safe\md5_file',
+ 'metaphone' => 'Safe\metaphone',
+ 'mime_content_type' => 'Safe\mime_content_type',
+ 'mkdir' => 'Safe\mkdir',
+ 'mktime' => 'Safe\mktime',
+ 'msg_queue_exists' => 'Safe\msg_queue_exists',
+ 'msg_receive' => 'Safe\msg_receive',
+ 'msg_remove_queue' => 'Safe\msg_remove_queue',
+ 'msg_send' => 'Safe\msg_send',
+ 'msg_set_queue' => 'Safe\msg_set_queue',
+ 'msql_affected_rows' => 'Safe\msql_affected_rows',
+ 'msql_close' => 'Safe\msql_close',
+ 'msql_connect' => 'Safe\msql_connect',
+ 'msql_create_db' => 'Safe\msql_create_db',
+ 'msql_data_seek' => 'Safe\msql_data_seek',
+ 'msql_db_query' => 'Safe\msql_db_query',
+ 'msql_drop_db' => 'Safe\msql_drop_db',
+ 'msql_field_len' => 'Safe\msql_field_len',
+ 'msql_field_name' => 'Safe\msql_field_name',
+ 'msql_field_seek' => 'Safe\msql_field_seek',
+ 'msql_field_table' => 'Safe\msql_field_table',
+ 'msql_field_type' => 'Safe\msql_field_type',
+ 'msql_free_result' => 'Safe\msql_free_result',
+ 'msql_pconnect' => 'Safe\msql_pconnect',
+ 'msql_query' => 'Safe\msql_query',
+ 'msql_select_db' => 'Safe\msql_select_db',
+ 'mysqli_get_cache_stats' => 'Safe\mysqli_get_cache_stats',
+ 'mysqli_get_client_stats' => 'Safe\mysqli_get_client_stats',
+ 'mysqlnd_ms_dump_servers' => 'Safe\mysqlnd_ms_dump_servers',
+ 'mysqlnd_ms_fabric_select_global' => 'Safe\mysqlnd_ms_fabric_select_global',
+ 'mysqlnd_ms_fabric_select_shard' => 'Safe\mysqlnd_ms_fabric_select_shard',
+ 'mysqlnd_ms_get_last_used_connection' => 'Safe\mysqlnd_ms_get_last_used_connection',
+ 'mysqlnd_qc_clear_cache' => 'Safe\mysqlnd_qc_clear_cache',
+ 'mysqlnd_qc_set_is_select' => 'Safe\mysqlnd_qc_set_is_select',
+ 'mysqlnd_qc_set_storage_handler' => 'Safe\mysqlnd_qc_set_storage_handler',
+ 'mysql_close' => 'Safe\mysql_close',
+ 'mysql_connect' => 'Safe\mysql_connect',
+ 'mysql_create_db' => 'Safe\mysql_create_db',
+ 'mysql_data_seek' => 'Safe\mysql_data_seek',
+ 'mysql_db_name' => 'Safe\mysql_db_name',
+ 'mysql_db_query' => 'Safe\mysql_db_query',
+ 'mysql_drop_db' => 'Safe\mysql_drop_db',
+ 'mysql_fetch_lengths' => 'Safe\mysql_fetch_lengths',
+ 'mysql_field_flags' => 'Safe\mysql_field_flags',
+ 'mysql_field_len' => 'Safe\mysql_field_len',
+ 'mysql_field_name' => 'Safe\mysql_field_name',
+ 'mysql_field_seek' => 'Safe\mysql_field_seek',
+ 'mysql_free_result' => 'Safe\mysql_free_result',
+ 'mysql_get_host_info' => 'Safe\mysql_get_host_info',
+ 'mysql_get_proto_info' => 'Safe\mysql_get_proto_info',
+ 'mysql_get_server_info' => 'Safe\mysql_get_server_info',
+ 'mysql_info' => 'Safe\mysql_info',
+ 'mysql_list_dbs' => 'Safe\mysql_list_dbs',
+ 'mysql_list_fields' => 'Safe\mysql_list_fields',
+ 'mysql_list_processes' => 'Safe\mysql_list_processes',
+ 'mysql_list_tables' => 'Safe\mysql_list_tables',
+ 'mysql_num_fields' => 'Safe\mysql_num_fields',
+ 'mysql_num_rows' => 'Safe\mysql_num_rows',
+ 'mysql_query' => 'Safe\mysql_query',
+ 'mysql_real_escape_string' => 'Safe\mysql_real_escape_string',
+ 'mysql_result' => 'Safe\mysql_result',
+ 'mysql_select_db' => 'Safe\mysql_select_db',
+ 'mysql_set_charset' => 'Safe\mysql_set_charset',
+ 'mysql_tablename' => 'Safe\mysql_tablename',
+ 'mysql_thread_id' => 'Safe\mysql_thread_id',
+ 'mysql_unbuffered_query' => 'Safe\mysql_unbuffered_query',
+ 'natcasesort' => 'Safe\natcasesort',
+ 'natsort' => 'Safe\natsort',
+ 'ob_end_clean' => 'Safe\ob_end_clean',
+ 'ob_end_flush' => 'Safe\ob_end_flush',
+ 'oci_bind_array_by_name' => 'Safe\oci_bind_array_by_name',
+ 'oci_bind_by_name' => 'Safe\oci_bind_by_name',
+ 'oci_cancel' => 'Safe\oci_cancel',
+ 'oci_close' => 'Safe\oci_close',
+ 'oci_commit' => 'Safe\oci_commit',
+ 'oci_connect' => 'Safe\oci_connect',
+ 'oci_define_by_name' => 'Safe\oci_define_by_name',
+ 'oci_execute' => 'Safe\oci_execute',
+ 'oci_fetch_all' => 'Safe\oci_fetch_all',
+ 'oci_field_name' => 'Safe\oci_field_name',
+ 'oci_field_precision' => 'Safe\oci_field_precision',
+ 'oci_field_scale' => 'Safe\oci_field_scale',
+ 'oci_field_size' => 'Safe\oci_field_size',
+ 'oci_field_type' => 'Safe\oci_field_type',
+ 'oci_field_type_raw' => 'Safe\oci_field_type_raw',
+ 'oci_free_descriptor' => 'Safe\oci_free_descriptor',
+ 'oci_free_statement' => 'Safe\oci_free_statement',
+ 'oci_new_collection' => 'Safe\oci_new_collection',
+ 'oci_new_connect' => 'Safe\oci_new_connect',
+ 'oci_new_cursor' => 'Safe\oci_new_cursor',
+ 'oci_new_descriptor' => 'Safe\oci_new_descriptor',
+ 'oci_num_fields' => 'Safe\oci_num_fields',
+ 'oci_num_rows' => 'Safe\oci_num_rows',
+ 'oci_parse' => 'Safe\oci_parse',
+ 'oci_pconnect' => 'Safe\oci_pconnect',
+ 'oci_result' => 'Safe\oci_result',
+ 'oci_rollback' => 'Safe\oci_rollback',
+ 'oci_server_version' => 'Safe\oci_server_version',
+ 'oci_set_action' => 'Safe\oci_set_action',
+ 'oci_set_call_timeout' => 'Safe\oci_set_call_timeout',
+ 'oci_set_client_identifier' => 'Safe\oci_set_client_identifier',
+ 'oci_set_client_info' => 'Safe\oci_set_client_info',
+ 'oci_set_db_operation' => 'Safe\oci_set_db_operation',
+ 'oci_set_edition' => 'Safe\oci_set_edition',
+ 'oci_set_module_name' => 'Safe\oci_set_module_name',
+ 'oci_set_prefetch' => 'Safe\oci_set_prefetch',
+ 'oci_statement_type' => 'Safe\oci_statement_type',
+ 'oci_unregister_taf_callback' => 'Safe\oci_unregister_taf_callback',
+ 'odbc_autocommit' => 'Safe\odbc_autocommit',
+ 'odbc_binmode' => 'Safe\odbc_binmode',
+ 'odbc_columnprivileges' => 'Safe\odbc_columnprivileges',
+ 'odbc_columns' => 'Safe\odbc_columns',
+ 'odbc_commit' => 'Safe\odbc_commit',
+ 'odbc_data_source' => 'Safe\odbc_data_source',
+ 'odbc_exec' => 'Safe\odbc_exec',
+ 'odbc_execute' => 'Safe\odbc_execute',
+ 'odbc_fetch_into' => 'Safe\odbc_fetch_into',
+ 'odbc_field_len' => 'Safe\odbc_field_len',
+ 'odbc_field_name' => 'Safe\odbc_field_name',
+ 'odbc_field_num' => 'Safe\odbc_field_num',
+ 'odbc_field_scale' => 'Safe\odbc_field_scale',
+ 'odbc_field_type' => 'Safe\odbc_field_type',
+ 'odbc_foreignkeys' => 'Safe\odbc_foreignkeys',
+ 'odbc_gettypeinfo' => 'Safe\odbc_gettypeinfo',
+ 'odbc_longreadlen' => 'Safe\odbc_longreadlen',
+ 'odbc_prepare' => 'Safe\odbc_prepare',
+ 'odbc_primarykeys' => 'Safe\odbc_primarykeys',
+ 'odbc_result' => 'Safe\odbc_result',
+ 'odbc_result_all' => 'Safe\odbc_result_all',
+ 'odbc_rollback' => 'Safe\odbc_rollback',
+ 'odbc_setoption' => 'Safe\odbc_setoption',
+ 'odbc_specialcolumns' => 'Safe\odbc_specialcolumns',
+ 'odbc_statistics' => 'Safe\odbc_statistics',
+ 'odbc_tableprivileges' => 'Safe\odbc_tableprivileges',
+ 'odbc_tables' => 'Safe\odbc_tables',
+ 'opcache_compile_file' => 'Safe\opcache_compile_file',
+ 'opcache_get_status' => 'Safe\opcache_get_status',
+ 'opendir' => 'Safe\opendir',
+ 'openlog' => 'Safe\openlog',
+ 'openssl_cipher_iv_length' => 'Safe\openssl_cipher_iv_length',
+ 'openssl_csr_export' => 'Safe\openssl_csr_export',
+ 'openssl_csr_export_to_file' => 'Safe\openssl_csr_export_to_file',
+ 'openssl_csr_get_subject' => 'Safe\openssl_csr_get_subject',
+ 'openssl_csr_new' => 'Safe\openssl_csr_new',
+ 'openssl_csr_sign' => 'Safe\openssl_csr_sign',
+ 'openssl_decrypt' => 'Safe\openssl_decrypt',
+ 'openssl_dh_compute_key' => 'Safe\openssl_dh_compute_key',
+ 'openssl_digest' => 'Safe\openssl_digest',
+ 'openssl_encrypt' => 'Safe\openssl_encrypt',
+ 'openssl_open' => 'Safe\openssl_open',
+ 'openssl_pbkdf2' => 'Safe\openssl_pbkdf2',
+ 'openssl_pkcs7_decrypt' => 'Safe\openssl_pkcs7_decrypt',
+ 'openssl_pkcs7_encrypt' => 'Safe\openssl_pkcs7_encrypt',
+ 'openssl_pkcs7_read' => 'Safe\openssl_pkcs7_read',
+ 'openssl_pkcs7_sign' => 'Safe\openssl_pkcs7_sign',
+ 'openssl_pkcs12_export' => 'Safe\openssl_pkcs12_export',
+ 'openssl_pkcs12_export_to_file' => 'Safe\openssl_pkcs12_export_to_file',
+ 'openssl_pkcs12_read' => 'Safe\openssl_pkcs12_read',
+ 'openssl_pkey_export' => 'Safe\openssl_pkey_export',
+ 'openssl_pkey_export_to_file' => 'Safe\openssl_pkey_export_to_file',
+ 'openssl_pkey_get_private' => 'Safe\openssl_pkey_get_private',
+ 'openssl_pkey_get_public' => 'Safe\openssl_pkey_get_public',
+ 'openssl_pkey_new' => 'Safe\openssl_pkey_new',
+ 'openssl_private_decrypt' => 'Safe\openssl_private_decrypt',
+ 'openssl_private_encrypt' => 'Safe\openssl_private_encrypt',
+ 'openssl_public_decrypt' => 'Safe\openssl_public_decrypt',
+ 'openssl_public_encrypt' => 'Safe\openssl_public_encrypt',
+ 'openssl_random_pseudo_bytes' => 'Safe\openssl_random_pseudo_bytes',
+ 'openssl_seal' => 'Safe\openssl_seal',
+ 'openssl_sign' => 'Safe\openssl_sign',
+ 'openssl_x509_export' => 'Safe\openssl_x509_export',
+ 'openssl_x509_export_to_file' => 'Safe\openssl_x509_export_to_file',
+ 'openssl_x509_fingerprint' => 'Safe\openssl_x509_fingerprint',
+ 'openssl_x509_read' => 'Safe\openssl_x509_read',
+ 'output_add_rewrite_var' => 'Safe\output_add_rewrite_var',
+ 'output_reset_rewrite_vars' => 'Safe\output_reset_rewrite_vars',
+ 'pack' => 'Safe\pack',
+ 'parse_ini_file' => 'Safe\parse_ini_file',
+ 'parse_ini_string' => 'Safe\parse_ini_string',
+ 'parse_url' => 'Safe\parse_url',
+ 'password_hash' => 'Safe\password_hash',
+ 'pcntl_exec' => 'Safe\pcntl_exec',
+ 'pcntl_getpriority' => 'Safe\pcntl_getpriority',
+ 'pcntl_setpriority' => 'Safe\pcntl_setpriority',
+ 'pcntl_signal_dispatch' => 'Safe\pcntl_signal_dispatch',
+ 'pcntl_sigprocmask' => 'Safe\pcntl_sigprocmask',
+ 'pcntl_strerror' => 'Safe\pcntl_strerror',
+ 'PDF_activate_item' => 'Safe\PDF_activate_item',
+ 'PDF_add_locallink' => 'Safe\PDF_add_locallink',
+ 'PDF_add_nameddest' => 'Safe\PDF_add_nameddest',
+ 'PDF_add_note' => 'Safe\PDF_add_note',
+ 'PDF_add_pdflink' => 'Safe\PDF_add_pdflink',
+ 'PDF_add_thumbnail' => 'Safe\PDF_add_thumbnail',
+ 'PDF_add_weblink' => 'Safe\PDF_add_weblink',
+ 'PDF_attach_file' => 'Safe\PDF_attach_file',
+ 'PDF_begin_layer' => 'Safe\PDF_begin_layer',
+ 'PDF_begin_page' => 'Safe\PDF_begin_page',
+ 'PDF_begin_page_ext' => 'Safe\PDF_begin_page_ext',
+ 'PDF_circle' => 'Safe\PDF_circle',
+ 'PDF_clip' => 'Safe\PDF_clip',
+ 'PDF_close' => 'Safe\PDF_close',
+ 'PDF_closepath' => 'Safe\PDF_closepath',
+ 'PDF_closepath_fill_stroke' => 'Safe\PDF_closepath_fill_stroke',
+ 'PDF_closepath_stroke' => 'Safe\PDF_closepath_stroke',
+ 'PDF_close_pdi' => 'Safe\PDF_close_pdi',
+ 'PDF_close_pdi_page' => 'Safe\PDF_close_pdi_page',
+ 'PDF_concat' => 'Safe\PDF_concat',
+ 'PDF_continue_text' => 'Safe\PDF_continue_text',
+ 'PDF_curveto' => 'Safe\PDF_curveto',
+ 'PDF_delete' => 'Safe\PDF_delete',
+ 'PDF_end_layer' => 'Safe\PDF_end_layer',
+ 'PDF_end_page' => 'Safe\PDF_end_page',
+ 'PDF_end_page_ext' => 'Safe\PDF_end_page_ext',
+ 'PDF_end_pattern' => 'Safe\PDF_end_pattern',
+ 'PDF_end_template' => 'Safe\PDF_end_template',
+ 'PDF_fill' => 'Safe\PDF_fill',
+ 'PDF_fill_stroke' => 'Safe\PDF_fill_stroke',
+ 'PDF_fit_image' => 'Safe\PDF_fit_image',
+ 'PDF_fit_pdi_page' => 'Safe\PDF_fit_pdi_page',
+ 'PDF_fit_textline' => 'Safe\PDF_fit_textline',
+ 'PDF_initgraphics' => 'Safe\PDF_initgraphics',
+ 'PDF_lineto' => 'Safe\PDF_lineto',
+ 'PDF_makespotcolor' => 'Safe\PDF_makespotcolor',
+ 'PDF_moveto' => 'Safe\PDF_moveto',
+ 'PDF_open_file' => 'Safe\PDF_open_file',
+ 'PDF_place_image' => 'Safe\PDF_place_image',
+ 'PDF_place_pdi_page' => 'Safe\PDF_place_pdi_page',
+ 'PDF_rect' => 'Safe\PDF_rect',
+ 'PDF_restore' => 'Safe\PDF_restore',
+ 'PDF_rotate' => 'Safe\PDF_rotate',
+ 'PDF_save' => 'Safe\PDF_save',
+ 'PDF_scale' => 'Safe\PDF_scale',
+ 'PDF_setcolor' => 'Safe\PDF_setcolor',
+ 'PDF_setdash' => 'Safe\PDF_setdash',
+ 'PDF_setdashpattern' => 'Safe\PDF_setdashpattern',
+ 'PDF_setflat' => 'Safe\PDF_setflat',
+ 'PDF_setfont' => 'Safe\PDF_setfont',
+ 'PDF_setgray' => 'Safe\PDF_setgray',
+ 'PDF_setgray_fill' => 'Safe\PDF_setgray_fill',
+ 'PDF_setgray_stroke' => 'Safe\PDF_setgray_stroke',
+ 'PDF_setlinejoin' => 'Safe\PDF_setlinejoin',
+ 'PDF_setlinewidth' => 'Safe\PDF_setlinewidth',
+ 'PDF_setmatrix' => 'Safe\PDF_setmatrix',
+ 'PDF_setmiterlimit' => 'Safe\PDF_setmiterlimit',
+ 'PDF_setrgbcolor' => 'Safe\PDF_setrgbcolor',
+ 'PDF_setrgbcolor_fill' => 'Safe\PDF_setrgbcolor_fill',
+ 'PDF_setrgbcolor_stroke' => 'Safe\PDF_setrgbcolor_stroke',
+ 'PDF_set_border_color' => 'Safe\PDF_set_border_color',
+ 'PDF_set_border_dash' => 'Safe\PDF_set_border_dash',
+ 'PDF_set_border_style' => 'Safe\PDF_set_border_style',
+ 'PDF_set_info' => 'Safe\PDF_set_info',
+ 'PDF_set_layer_dependency' => 'Safe\PDF_set_layer_dependency',
+ 'PDF_set_parameter' => 'Safe\PDF_set_parameter',
+ 'PDF_set_text_pos' => 'Safe\PDF_set_text_pos',
+ 'PDF_set_value' => 'Safe\PDF_set_value',
+ 'PDF_show' => 'Safe\PDF_show',
+ 'PDF_show_xy' => 'Safe\PDF_show_xy',
+ 'PDF_skew' => 'Safe\PDF_skew',
+ 'PDF_stroke' => 'Safe\PDF_stroke',
+ 'pg_cancel_query' => 'Safe\pg_cancel_query',
+ 'pg_client_encoding' => 'Safe\pg_client_encoding',
+ 'pg_close' => 'Safe\pg_close',
+ 'pg_connect' => 'Safe\pg_connect',
+ 'pg_connection_reset' => 'Safe\pg_connection_reset',
+ 'pg_convert' => 'Safe\pg_convert',
+ 'pg_copy_from' => 'Safe\pg_copy_from',
+ 'pg_copy_to' => 'Safe\pg_copy_to',
+ 'pg_dbname' => 'Safe\pg_dbname',
+ 'pg_delete' => 'Safe\pg_delete',
+ 'pg_end_copy' => 'Safe\pg_end_copy',
+ 'pg_execute' => 'Safe\pg_execute',
+ 'pg_field_name' => 'Safe\pg_field_name',
+ 'pg_field_table' => 'Safe\pg_field_table',
+ 'pg_field_type' => 'Safe\pg_field_type',
+ 'pg_flush' => 'Safe\pg_flush',
+ 'pg_free_result' => 'Safe\pg_free_result',
+ 'pg_host' => 'Safe\pg_host',
+ 'pg_insert' => 'Safe\pg_insert',
+ 'pg_last_error' => 'Safe\pg_last_error',
+ 'pg_last_notice' => 'Safe\pg_last_notice',
+ 'pg_last_oid' => 'Safe\pg_last_oid',
+ 'pg_lo_close' => 'Safe\pg_lo_close',
+ 'pg_lo_export' => 'Safe\pg_lo_export',
+ 'pg_lo_import' => 'Safe\pg_lo_import',
+ 'pg_lo_open' => 'Safe\pg_lo_open',
+ 'pg_lo_read' => 'Safe\pg_lo_read',
+ 'pg_lo_read_all' => 'Safe\pg_lo_read_all',
+ 'pg_lo_seek' => 'Safe\pg_lo_seek',
+ 'pg_lo_truncate' => 'Safe\pg_lo_truncate',
+ 'pg_lo_unlink' => 'Safe\pg_lo_unlink',
+ 'pg_lo_write' => 'Safe\pg_lo_write',
+ 'pg_meta_data' => 'Safe\pg_meta_data',
+ 'pg_options' => 'Safe\pg_options',
+ 'pg_parameter_status' => 'Safe\pg_parameter_status',
+ 'pg_pconnect' => 'Safe\pg_pconnect',
+ 'pg_ping' => 'Safe\pg_ping',
+ 'pg_port' => 'Safe\pg_port',
+ 'pg_prepare' => 'Safe\pg_prepare',
+ 'pg_put_line' => 'Safe\pg_put_line',
+ 'pg_query' => 'Safe\pg_query',
+ 'pg_query_params' => 'Safe\pg_query_params',
+ 'pg_result_error_field' => 'Safe\pg_result_error_field',
+ 'pg_result_seek' => 'Safe\pg_result_seek',
+ 'pg_select' => 'Safe\pg_select',
+ 'pg_send_execute' => 'Safe\pg_send_execute',
+ 'pg_send_prepare' => 'Safe\pg_send_prepare',
+ 'pg_send_query' => 'Safe\pg_send_query',
+ 'pg_send_query_params' => 'Safe\pg_send_query_params',
+ 'pg_socket' => 'Safe\pg_socket',
+ 'pg_trace' => 'Safe\pg_trace',
+ 'pg_tty' => 'Safe\pg_tty',
+ 'pg_update' => 'Safe\pg_update',
+ 'pg_version' => 'Safe\pg_version',
+ 'phpcredits' => 'Safe\phpcredits',
+ 'phpinfo' => 'Safe\phpinfo',
+ 'png2wbmp' => 'Safe\png2wbmp',
+ 'posix_access' => 'Safe\posix_access',
+ 'posix_getgrnam' => 'Safe\posix_getgrnam',
+ 'posix_getpgid' => 'Safe\posix_getpgid',
+ 'posix_initgroups' => 'Safe\posix_initgroups',
+ 'posix_kill' => 'Safe\posix_kill',
+ 'posix_mkfifo' => 'Safe\posix_mkfifo',
+ 'posix_mknod' => 'Safe\posix_mknod',
+ 'posix_setegid' => 'Safe\posix_setegid',
+ 'posix_seteuid' => 'Safe\posix_seteuid',
+ 'posix_setgid' => 'Safe\posix_setgid',
+ 'posix_setpgid' => 'Safe\posix_setpgid',
+ 'posix_setrlimit' => 'Safe\posix_setrlimit',
+ 'posix_setuid' => 'Safe\posix_setuid',
+ 'preg_match' => 'Safe\preg_match',
+ 'preg_match_all' => 'Safe\preg_match_all',
+ 'preg_replace' => 'Safe\preg_replace',
+ 'preg_split' => 'Safe\preg_split',
+ 'proc_get_status' => 'Safe\proc_get_status',
+ 'proc_nice' => 'Safe\proc_nice',
+ 'pspell_add_to_personal' => 'Safe\pspell_add_to_personal',
+ 'pspell_add_to_session' => 'Safe\pspell_add_to_session',
+ 'pspell_clear_session' => 'Safe\pspell_clear_session',
+ 'pspell_config_create' => 'Safe\pspell_config_create',
+ 'pspell_config_data_dir' => 'Safe\pspell_config_data_dir',
+ 'pspell_config_dict_dir' => 'Safe\pspell_config_dict_dir',
+ 'pspell_config_ignore' => 'Safe\pspell_config_ignore',
+ 'pspell_config_mode' => 'Safe\pspell_config_mode',
+ 'pspell_config_personal' => 'Safe\pspell_config_personal',
+ 'pspell_config_repl' => 'Safe\pspell_config_repl',
+ 'pspell_config_runtogether' => 'Safe\pspell_config_runtogether',
+ 'pspell_config_save_repl' => 'Safe\pspell_config_save_repl',
+ 'pspell_new' => 'Safe\pspell_new',
+ 'pspell_new_config' => 'Safe\pspell_new_config',
+ 'pspell_save_wordlist' => 'Safe\pspell_save_wordlist',
+ 'pspell_store_replacement' => 'Safe\pspell_store_replacement',
+ 'ps_add_launchlink' => 'Safe\ps_add_launchlink',
+ 'ps_add_locallink' => 'Safe\ps_add_locallink',
+ 'ps_add_note' => 'Safe\ps_add_note',
+ 'ps_add_pdflink' => 'Safe\ps_add_pdflink',
+ 'ps_add_weblink' => 'Safe\ps_add_weblink',
+ 'ps_arc' => 'Safe\ps_arc',
+ 'ps_arcn' => 'Safe\ps_arcn',
+ 'ps_begin_page' => 'Safe\ps_begin_page',
+ 'ps_begin_pattern' => 'Safe\ps_begin_pattern',
+ 'ps_begin_template' => 'Safe\ps_begin_template',
+ 'ps_circle' => 'Safe\ps_circle',
+ 'ps_clip' => 'Safe\ps_clip',
+ 'ps_close' => 'Safe\ps_close',
+ 'ps_closepath' => 'Safe\ps_closepath',
+ 'ps_closepath_stroke' => 'Safe\ps_closepath_stroke',
+ 'ps_close_image' => 'Safe\ps_close_image',
+ 'ps_continue_text' => 'Safe\ps_continue_text',
+ 'ps_curveto' => 'Safe\ps_curveto',
+ 'ps_delete' => 'Safe\ps_delete',
+ 'ps_end_page' => 'Safe\ps_end_page',
+ 'ps_end_pattern' => 'Safe\ps_end_pattern',
+ 'ps_end_template' => 'Safe\ps_end_template',
+ 'ps_fill' => 'Safe\ps_fill',
+ 'ps_fill_stroke' => 'Safe\ps_fill_stroke',
+ 'ps_get_parameter' => 'Safe\ps_get_parameter',
+ 'ps_hyphenate' => 'Safe\ps_hyphenate',
+ 'ps_include_file' => 'Safe\ps_include_file',
+ 'ps_lineto' => 'Safe\ps_lineto',
+ 'ps_moveto' => 'Safe\ps_moveto',
+ 'ps_new' => 'Safe\ps_new',
+ 'ps_open_file' => 'Safe\ps_open_file',
+ 'ps_place_image' => 'Safe\ps_place_image',
+ 'ps_rect' => 'Safe\ps_rect',
+ 'ps_restore' => 'Safe\ps_restore',
+ 'ps_rotate' => 'Safe\ps_rotate',
+ 'ps_save' => 'Safe\ps_save',
+ 'ps_scale' => 'Safe\ps_scale',
+ 'ps_setcolor' => 'Safe\ps_setcolor',
+ 'ps_setdash' => 'Safe\ps_setdash',
+ 'ps_setflat' => 'Safe\ps_setflat',
+ 'ps_setfont' => 'Safe\ps_setfont',
+ 'ps_setgray' => 'Safe\ps_setgray',
+ 'ps_setlinecap' => 'Safe\ps_setlinecap',
+ 'ps_setlinejoin' => 'Safe\ps_setlinejoin',
+ 'ps_setlinewidth' => 'Safe\ps_setlinewidth',
+ 'ps_setmiterlimit' => 'Safe\ps_setmiterlimit',
+ 'ps_setoverprintmode' => 'Safe\ps_setoverprintmode',
+ 'ps_setpolydash' => 'Safe\ps_setpolydash',
+ 'ps_set_border_color' => 'Safe\ps_set_border_color',
+ 'ps_set_border_dash' => 'Safe\ps_set_border_dash',
+ 'ps_set_border_style' => 'Safe\ps_set_border_style',
+ 'ps_set_info' => 'Safe\ps_set_info',
+ 'ps_set_parameter' => 'Safe\ps_set_parameter',
+ 'ps_set_text_pos' => 'Safe\ps_set_text_pos',
+ 'ps_set_value' => 'Safe\ps_set_value',
+ 'ps_shading' => 'Safe\ps_shading',
+ 'ps_shading_pattern' => 'Safe\ps_shading_pattern',
+ 'ps_shfill' => 'Safe\ps_shfill',
+ 'ps_show' => 'Safe\ps_show',
+ 'ps_show2' => 'Safe\ps_show2',
+ 'ps_show_xy' => 'Safe\ps_show_xy',
+ 'ps_show_xy2' => 'Safe\ps_show_xy2',
+ 'ps_stroke' => 'Safe\ps_stroke',
+ 'ps_symbol' => 'Safe\ps_symbol',
+ 'ps_translate' => 'Safe\ps_translate',
+ 'putenv' => 'Safe\putenv',
+ 'readfile' => 'Safe\readfile',
+ 'readgzfile' => 'Safe\readgzfile',
+ 'readline_add_history' => 'Safe\readline_add_history',
+ 'readline_callback_handler_install' => 'Safe\readline_callback_handler_install',
+ 'readline_clear_history' => 'Safe\readline_clear_history',
+ 'readline_completion_function' => 'Safe\readline_completion_function',
+ 'readline_read_history' => 'Safe\readline_read_history',
+ 'readline_write_history' => 'Safe\readline_write_history',
+ 'readlink' => 'Safe\readlink',
+ 'realpath' => 'Safe\realpath',
+ 'register_tick_function' => 'Safe\register_tick_function',
+ 'rename' => 'Safe\rename',
+ 'rewind' => 'Safe\rewind',
+ 'rewinddir' => 'Safe\rewinddir',
+ 'rmdir' => 'Safe\rmdir',
+ 'rpmaddtag' => 'Safe\rpmaddtag',
+ 'rrd_create' => 'Safe\rrd_create',
+ 'rsort' => 'Safe\rsort',
+ 'sapi_windows_cp_conv' => 'Safe\sapi_windows_cp_conv',
+ 'sapi_windows_cp_set' => 'Safe\sapi_windows_cp_set',
+ 'sapi_windows_generate_ctrl_event' => 'Safe\sapi_windows_generate_ctrl_event',
+ 'sapi_windows_vt100_support' => 'Safe\sapi_windows_vt100_support',
+ 'scandir' => 'Safe\scandir',
+ 'sem_acquire' => 'Safe\sem_acquire',
+ 'sem_get' => 'Safe\sem_get',
+ 'sem_release' => 'Safe\sem_release',
+ 'sem_remove' => 'Safe\sem_remove',
+ 'session_abort' => 'Safe\session_abort',
+ 'session_decode' => 'Safe\session_decode',
+ 'session_destroy' => 'Safe\session_destroy',
+ 'session_regenerate_id' => 'Safe\session_regenerate_id',
+ 'session_reset' => 'Safe\session_reset',
+ 'session_unset' => 'Safe\session_unset',
+ 'session_write_close' => 'Safe\session_write_close',
+ 'settype' => 'Safe\settype',
+ 'set_include_path' => 'Safe\set_include_path',
+ 'set_time_limit' => 'Safe\set_time_limit',
+ 'sha1_file' => 'Safe\sha1_file',
+ 'shmop_delete' => 'Safe\shmop_delete',
+ 'shmop_read' => 'Safe\shmop_read',
+ 'shmop_write' => 'Safe\shmop_write',
+ 'shm_put_var' => 'Safe\shm_put_var',
+ 'shm_remove' => 'Safe\shm_remove',
+ 'shm_remove_var' => 'Safe\shm_remove_var',
+ 'shuffle' => 'Safe\shuffle',
+ 'simplexml_import_dom' => 'Safe\simplexml_import_dom',
+ 'simplexml_load_file' => 'Safe\simplexml_load_file',
+ 'simplexml_load_string' => 'Safe\simplexml_load_string',
+ 'sleep' => 'Safe\sleep',
+ 'socket_accept' => 'Safe\socket_accept',
+ 'socket_addrinfo_bind' => 'Safe\socket_addrinfo_bind',
+ 'socket_addrinfo_connect' => 'Safe\socket_addrinfo_connect',
+ 'socket_bind' => 'Safe\socket_bind',
+ 'socket_connect' => 'Safe\socket_connect',
+ 'socket_create' => 'Safe\socket_create',
+ 'socket_create_listen' => 'Safe\socket_create_listen',
+ 'socket_create_pair' => 'Safe\socket_create_pair',
+ 'socket_export_stream' => 'Safe\socket_export_stream',
+ 'socket_getpeername' => 'Safe\socket_getpeername',
+ 'socket_getsockname' => 'Safe\socket_getsockname',
+ 'socket_get_option' => 'Safe\socket_get_option',
+ 'socket_import_stream' => 'Safe\socket_import_stream',
+ 'socket_listen' => 'Safe\socket_listen',
+ 'socket_read' => 'Safe\socket_read',
+ 'socket_send' => 'Safe\socket_send',
+ 'socket_sendmsg' => 'Safe\socket_sendmsg',
+ 'socket_sendto' => 'Safe\socket_sendto',
+ 'socket_set_block' => 'Safe\socket_set_block',
+ 'socket_set_nonblock' => 'Safe\socket_set_nonblock',
+ 'socket_set_option' => 'Safe\socket_set_option',
+ 'socket_shutdown' => 'Safe\socket_shutdown',
+ 'socket_write' => 'Safe\socket_write',
+ 'socket_wsaprotocol_info_export' => 'Safe\socket_wsaprotocol_info_export',
+ 'socket_wsaprotocol_info_import' => 'Safe\socket_wsaprotocol_info_import',
+ 'socket_wsaprotocol_info_release' => 'Safe\socket_wsaprotocol_info_release',
+ 'sodium_crypto_pwhash' => 'Safe\sodium_crypto_pwhash',
+ 'sodium_crypto_pwhash_str' => 'Safe\sodium_crypto_pwhash_str',
+ 'solr_get_version' => 'Safe\solr_get_version',
+ 'sort' => 'Safe\sort',
+ 'soundex' => 'Safe\soundex',
+ 'spl_autoload_register' => 'Safe\spl_autoload_register',
+ 'spl_autoload_unregister' => 'Safe\spl_autoload_unregister',
+ 'sprintf' => 'Safe\sprintf',
+ 'sqlsrv_begin_transaction' => 'Safe\sqlsrv_begin_transaction',
+ 'sqlsrv_cancel' => 'Safe\sqlsrv_cancel',
+ 'sqlsrv_client_info' => 'Safe\sqlsrv_client_info',
+ 'sqlsrv_close' => 'Safe\sqlsrv_close',
+ 'sqlsrv_commit' => 'Safe\sqlsrv_commit',
+ 'sqlsrv_configure' => 'Safe\sqlsrv_configure',
+ 'sqlsrv_execute' => 'Safe\sqlsrv_execute',
+ 'sqlsrv_free_stmt' => 'Safe\sqlsrv_free_stmt',
+ 'sqlsrv_get_field' => 'Safe\sqlsrv_get_field',
+ 'sqlsrv_next_result' => 'Safe\sqlsrv_next_result',
+ 'sqlsrv_num_fields' => 'Safe\sqlsrv_num_fields',
+ 'sqlsrv_num_rows' => 'Safe\sqlsrv_num_rows',
+ 'sqlsrv_prepare' => 'Safe\sqlsrv_prepare',
+ 'sqlsrv_query' => 'Safe\sqlsrv_query',
+ 'sqlsrv_rollback' => 'Safe\sqlsrv_rollback',
+ 'ssdeep_fuzzy_compare' => 'Safe\ssdeep_fuzzy_compare',
+ 'ssdeep_fuzzy_hash' => 'Safe\ssdeep_fuzzy_hash',
+ 'ssdeep_fuzzy_hash_filename' => 'Safe\ssdeep_fuzzy_hash_filename',
+ 'ssh2_auth_agent' => 'Safe\ssh2_auth_agent',
+ 'ssh2_auth_hostbased_file' => 'Safe\ssh2_auth_hostbased_file',
+ 'ssh2_auth_password' => 'Safe\ssh2_auth_password',
+ 'ssh2_auth_pubkey_file' => 'Safe\ssh2_auth_pubkey_file',
+ 'ssh2_connect' => 'Safe\ssh2_connect',
+ 'ssh2_disconnect' => 'Safe\ssh2_disconnect',
+ 'ssh2_exec' => 'Safe\ssh2_exec',
+ 'ssh2_publickey_add' => 'Safe\ssh2_publickey_add',
+ 'ssh2_publickey_init' => 'Safe\ssh2_publickey_init',
+ 'ssh2_publickey_remove' => 'Safe\ssh2_publickey_remove',
+ 'ssh2_scp_recv' => 'Safe\ssh2_scp_recv',
+ 'ssh2_scp_send' => 'Safe\ssh2_scp_send',
+ 'ssh2_sftp' => 'Safe\ssh2_sftp',
+ 'ssh2_sftp_chmod' => 'Safe\ssh2_sftp_chmod',
+ 'ssh2_sftp_mkdir' => 'Safe\ssh2_sftp_mkdir',
+ 'ssh2_sftp_rename' => 'Safe\ssh2_sftp_rename',
+ 'ssh2_sftp_rmdir' => 'Safe\ssh2_sftp_rmdir',
+ 'ssh2_sftp_symlink' => 'Safe\ssh2_sftp_symlink',
+ 'ssh2_sftp_unlink' => 'Safe\ssh2_sftp_unlink',
+ 'stream_context_set_params' => 'Safe\stream_context_set_params',
+ 'stream_copy_to_stream' => 'Safe\stream_copy_to_stream',
+ 'stream_filter_append' => 'Safe\stream_filter_append',
+ 'stream_filter_prepend' => 'Safe\stream_filter_prepend',
+ 'stream_filter_register' => 'Safe\stream_filter_register',
+ 'stream_filter_remove' => 'Safe\stream_filter_remove',
+ 'stream_get_contents' => 'Safe\stream_get_contents',
+ 'stream_isatty' => 'Safe\stream_isatty',
+ 'stream_resolve_include_path' => 'Safe\stream_resolve_include_path',
+ 'stream_set_blocking' => 'Safe\stream_set_blocking',
+ 'stream_set_timeout' => 'Safe\stream_set_timeout',
+ 'stream_socket_accept' => 'Safe\stream_socket_accept',
+ 'stream_socket_client' => 'Safe\stream_socket_client',
+ 'stream_socket_pair' => 'Safe\stream_socket_pair',
+ 'stream_socket_server' => 'Safe\stream_socket_server',
+ 'stream_socket_shutdown' => 'Safe\stream_socket_shutdown',
+ 'stream_supports_lock' => 'Safe\stream_supports_lock',
+ 'stream_wrapper_register' => 'Safe\stream_wrapper_register',
+ 'stream_wrapper_restore' => 'Safe\stream_wrapper_restore',
+ 'stream_wrapper_unregister' => 'Safe\stream_wrapper_unregister',
+ 'strptime' => 'Safe\strptime',
+ 'strtotime' => 'Safe\strtotime',
+ 'substr' => 'Safe\substr',
+ 'swoole_async_write' => 'Safe\swoole_async_write',
+ 'swoole_async_writefile' => 'Safe\swoole_async_writefile',
+ 'swoole_event_defer' => 'Safe\swoole_event_defer',
+ 'swoole_event_del' => 'Safe\swoole_event_del',
+ 'swoole_event_write' => 'Safe\swoole_event_write',
+ 'symlink' => 'Safe\symlink',
+ 'syslog' => 'Safe\syslog',
+ 'system' => 'Safe\system',
+ 'tempnam' => 'Safe\tempnam',
+ 'timezone_name_from_abbr' => 'Safe\timezone_name_from_abbr',
+ 'time_nanosleep' => 'Safe\time_nanosleep',
+ 'time_sleep_until' => 'Safe\time_sleep_until',
+ 'tmpfile' => 'Safe\tmpfile',
+ 'touch' => 'Safe\touch',
+ 'uasort' => 'Safe\uasort',
+ 'uksort' => 'Safe\uksort',
+ 'unlink' => 'Safe\unlink',
+ 'unpack' => 'Safe\unpack',
+ 'uopz_extend' => 'Safe\uopz_extend',
+ 'uopz_implement' => 'Safe\uopz_implement',
+ 'usort' => 'Safe\usort',
+ 'virtual' => 'Safe\virtual',
+ 'vsprintf' => 'Safe\vsprintf',
+ 'xdiff_file_bdiff' => 'Safe\xdiff_file_bdiff',
+ 'xdiff_file_bpatch' => 'Safe\xdiff_file_bpatch',
+ 'xdiff_file_diff' => 'Safe\xdiff_file_diff',
+ 'xdiff_file_diff_binary' => 'Safe\xdiff_file_diff_binary',
+ 'xdiff_file_patch_binary' => 'Safe\xdiff_file_patch_binary',
+ 'xdiff_file_rabdiff' => 'Safe\xdiff_file_rabdiff',
+ 'xdiff_string_bpatch' => 'Safe\xdiff_string_bpatch',
+ 'xdiff_string_patch' => 'Safe\xdiff_string_patch',
+ 'xdiff_string_patch_binary' => 'Safe\xdiff_string_patch_binary',
+ 'xmlrpc_set_type' => 'Safe\xmlrpc_set_type',
+ 'xml_parser_create' => 'Safe\xml_parser_create',
+ 'xml_parser_create_ns' => 'Safe\xml_parser_create_ns',
+ 'xml_set_object' => 'Safe\xml_set_object',
+ 'yaml_parse' => 'Safe\yaml_parse',
+ 'yaml_parse_file' => 'Safe\yaml_parse_file',
+ 'yaml_parse_url' => 'Safe\yaml_parse_url',
+ 'yaz_ccl_parse' => 'Safe\yaz_ccl_parse',
+ 'yaz_close' => 'Safe\yaz_close',
+ 'yaz_connect' => 'Safe\yaz_connect',
+ 'yaz_database' => 'Safe\yaz_database',
+ 'yaz_element' => 'Safe\yaz_element',
+ 'yaz_present' => 'Safe\yaz_present',
+ 'yaz_search' => 'Safe\yaz_search',
+ 'yaz_wait' => 'Safe\yaz_wait',
+ 'zip_entry_close' => 'Safe\zip_entry_close',
+ 'zip_entry_open' => 'Safe\zip_entry_open',
+ 'zip_entry_read' => 'Safe\zip_entry_read',
+ 'zlib_decode' => 'Safe\zlib_decode',
+]]]);
+};
diff --git a/web-auth/webauthn-lib/src/AttestationStatement/AppleAttestationStatementSupport.php b/web-auth/webauthn-lib/src/AttestationStatement/AppleAttestationStatementSupport.php
new file mode 100644
index 000000000..3f942e472
--- /dev/null
+++ b/web-auth/webauthn-lib/src/AttestationStatement/AppleAttestationStatementSupport.php
@@ -0,0 +1,120 @@
+decoder = new Decoder(new TagObjectManager(), new OtherObjectManager());
+ }
+
+ public function name(): string
+ {
+ return 'apple';
+ }
+
+ /**
+ * @param mixed[] $attestation
+ */
+ public function load(array $attestation): AttestationStatement
+ {
+ Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object');
+ foreach (['x5c'] as $key) {
+ Assertion::keyExists($attestation['attStmt'], $key, sprintf('The attestation statement value "%s" is missing.', $key));
+ }
+ $certificates = $attestation['attStmt']['x5c'];
+ Assertion::isArray($certificates, 'The attestation statement value "x5c" must be a list with at least one certificate.');
+ Assertion::greaterThan(count($certificates), 0, 'The attestation statement value "x5c" must be a list with at least one certificate.');
+ Assertion::allString($certificates, 'The attestation statement value "x5c" must be a list with at least one certificate.');
+ $certificates = CertificateToolbox::convertAllDERToPEM($certificates);
+
+ return AttestationStatement::createAnonymizationCA($attestation['fmt'], $attestation['attStmt'], new CertificateTrustPath($certificates));
+ }
+
+ public function isValid(string $clientDataJSONHash, AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData): bool
+ {
+ $trustPath = $attestationStatement->getTrustPath();
+ Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path');
+
+ $certificates = $trustPath->getCertificates();
+
+ //Decode leaf attestation certificate
+ $leaf = $certificates[0];
+
+ $this->checkCertificateAndGetPublicKey($leaf, $clientDataJSONHash, $authenticatorData);
+
+ return true;
+ }
+
+ private function checkCertificateAndGetPublicKey(string $certificate, string $clientDataHash, AuthenticatorData $authenticatorData): void
+ {
+ $resource = openssl_pkey_get_public($certificate);
+ $details = openssl_pkey_get_details($resource);
+ Assertion::isArray($details, 'Unable to read the certificate');
+
+ //Check that authData publicKey matches the public key in the attestation certificate
+ $attestedCredentialData = $authenticatorData->getAttestedCredentialData();
+ Assertion::notNull($attestedCredentialData, 'No attested credential data found');
+ $publicKeyData = $attestedCredentialData->getCredentialPublicKey();
+ Assertion::notNull($publicKeyData, 'No attested public key found');
+ $publicDataStream = new StringStream($publicKeyData);
+ $coseKey = $this->decoder->decode($publicDataStream)->getNormalizedData(false);
+ Assertion::true($publicDataStream->isEOF(), 'Invalid public key data. Presence of extra bytes.');
+ $publicDataStream->close();
+ $publicKey = Key::createFromData($coseKey);
+
+ Assertion::true(($publicKey instanceof Ec2Key) || ($publicKey instanceof RsaKey), 'Unsupported key type');
+
+ //We check the attested key corresponds to the key in the certificate
+ Assertion::eq($publicKey->asPEM(), $details['key'], 'Invalid key');
+
+ /*---------------------------*/
+ $certDetails = openssl_x509_parse($certificate);
+
+ //Find Apple Extension with OID “1.2.840.113635.100.8.2” in certificate extensions
+ Assertion::isArray($certDetails, 'The certificate is not valid');
+ Assertion::keyExists($certDetails, 'extensions', 'The certificate has no extension');
+ Assertion::isArray($certDetails['extensions'], 'The certificate has no extension');
+ Assertion::keyExists($certDetails['extensions'], '1.2.840.113635.100.8.2', 'The certificate extension "1.2.840.113635.100.8.2" is missing');
+ $extension = $certDetails['extensions']['1.2.840.113635.100.8.2'];
+
+ $nonceToHash = $authenticatorData->getAuthData().$clientDataHash;
+ $nonce = hash('sha256', $nonceToHash);
+
+ //'3024a1220420' corresponds to the Sequence+Explicitly Tagged Object + Octet Object
+ Assertion::eq('3024a1220420'.$nonce, bin2hex($extension), 'The client data hash is not valid');
+ }
+}
diff --git a/web-auth/webauthn-lib/src/CertificateChainChecker/CertificateChainChecker.php b/web-auth/webauthn-lib/src/CertificateChainChecker/CertificateChainChecker.php
new file mode 100644
index 000000000..fb33b47df
--- /dev/null
+++ b/web-auth/webauthn-lib/src/CertificateChainChecker/CertificateChainChecker.php
@@ -0,0 +1,23 @@
+client = $client;
+ $this->requestFactory = $requestFactory;
+ }
+
+ public function addRootCertificate(string $certificate): self
+ {
+ $this->rootCertificates[] = $certificate;
+
+ return $this;
+ }
+
+ /**
+ * @param string[] $authenticatorCertificates
+ * @param string[] $trustedCertificates
+ */
+ public function check(array $authenticatorCertificates, array $trustedCertificates): void
+ {
+ if (0 === count($trustedCertificates)) {
+ $this->checkCertificatesValidity($authenticatorCertificates, true);
+
+ return;
+ }
+ $this->checkCertificatesValidity($authenticatorCertificates, false);
+
+ $hasCrls = false;
+ $processArguments = ['-no-CAfile', '-no-CApath'];
+
+ $caDirname = $this->createTemporaryDirectory();
+ $processArguments[] = '--CApath';
+ $processArguments[] = $caDirname;
+
+ foreach ($trustedCertificates as $certificate) {
+ $this->saveToTemporaryFile($caDirname, $certificate, 'webauthn-trusted-', '.pem');
+ $crl = $this->getCrls($certificate);
+ if ('' !== $crl) {
+ $hasCrls = true;
+ $this->saveToTemporaryFile($caDirname, $crl, 'webauthn-trusted-crl-', '.crl');
+ }
+ }
+
+ $rehashProcess = new Process(['openssl', 'rehash', $caDirname]);
+ $rehashProcess->run();
+ while ($rehashProcess->isRunning()) {
+ //Just wait
+ }
+ if (!$rehashProcess->isSuccessful()) {
+ throw new InvalidArgumentException('Invalid certificate or certificate chain');
+ }
+
+ $filenames = [];
+ $leafCertificate = array_shift($authenticatorCertificates);
+ $leafFilename = $this->saveToTemporaryFile(sys_get_temp_dir(), $leafCertificate, 'webauthn-leaf-', '.pem');
+ $crl = $this->getCrls($leafCertificate);
+ if ('' !== $crl) {
+ $hasCrls = true;
+ $this->saveToTemporaryFile($caDirname, $crl, 'webauthn-leaf-crl-', '.pem');
+ }
+ $filenames[] = $leafFilename;
+
+ foreach ($authenticatorCertificates as $certificate) {
+ $untrustedFilename = $this->saveToTemporaryFile(sys_get_temp_dir(), $certificate, 'webauthn-untrusted-', '.pem');
+ $crl = $this->getCrls($certificate);
+ if ('' !== $crl) {
+ $hasCrls = true;
+ $this->saveToTemporaryFile($caDirname, $crl, 'webauthn-untrusted-crl-', '.pem');
+ }
+ $processArguments[] = '-untrusted';
+ $processArguments[] = $untrustedFilename;
+ $filenames[] = $untrustedFilename;
+ }
+
+ $processArguments[] = $leafFilename;
+ if ($hasCrls) {
+ array_unshift($processArguments, '-crl_check');
+ array_unshift($processArguments, '-crl_check_all');
+ //array_unshift($processArguments, '-crl_download');
+ array_unshift($processArguments, '-extended_crl');
+ }
+ array_unshift($processArguments, 'openssl', 'verify');
+
+ $process = new Process($processArguments);
+ $process->run();
+ while ($process->isRunning()) {
+ //Just wait
+ }
+
+ foreach ($filenames as $filename) {
+ try {
+ unlink($filename);
+ } catch (FilesystemException $e) {
+ continue;
+ }
+ }
+ $this->deleteDirectory($caDirname);
+
+ if (!$process->isSuccessful()) {
+ throw new InvalidArgumentException('Invalid certificate or certificate chain');
+ }
+ }
+
+ /**
+ * @param string[] $certificates
+ */
+ private function checkCertificatesValidity(array $certificates, bool $allowRootCertificate): void
+ {
+ foreach ($certificates as $certificate) {
+ $parsed = openssl_x509_parse($certificate);
+ Assertion::isArray($parsed, 'Unable to read the certificate');
+ if (false === $allowRootCertificate) {
+ $this->checkRootCertificate($parsed);
+ }
+
+ Assertion::keyExists($parsed, 'validTo_time_t', 'The certificate has no validity period');
+ Assertion::keyExists($parsed, 'validFrom_time_t', 'The certificate has no validity period');
+ Assertion::lessOrEqualThan(time(), $parsed['validTo_time_t'], 'The certificate expired');
+ Assertion::greaterOrEqualThan(time(), $parsed['validFrom_time_t'], 'The certificate is not usable yet');
+ }
+ }
+
+ /**
+ * @param array $parsed
+ */
+ private function checkRootCertificate(array $parsed): void
+ {
+ Assertion::keyExists($parsed, 'subject', 'The certificate has no subject');
+ Assertion::keyExists($parsed, 'issuer', 'The certificate has no issuer');
+ $subject = $parsed['subject'];
+ $issuer = $parsed['issuer'];
+ ksort($subject);
+ ksort($issuer);
+ Assertion::notEq($subject, $issuer, 'Root certificates are not allowed');
+ }
+
+ private function createTemporaryDirectory(): string
+ {
+ $caDir = tempnam(sys_get_temp_dir(), 'webauthn-ca-');
+ if (file_exists($caDir)) {
+ unlink($caDir);
+ }
+ mkdir($caDir);
+ if (!is_dir($caDir)) {
+ throw new RuntimeException(sprintf('Directory "%s" was not created', $caDir));
+ }
+
+ return $caDir;
+ }
+
+ private function deleteDirectory(string $dirname): void
+ {
+ $rehashProcess = new Process(['rm', '-rf', $dirname]);
+ $rehashProcess->run();
+ while ($rehashProcess->isRunning()) {
+ //Just wait
+ }
+ }
+
+ private function saveToTemporaryFile(string $folder, string $certificate, string $prefix, string $suffix): string
+ {
+ $filename = tempnam($folder, $prefix);
+ rename($filename, $filename.$suffix);
+ file_put_contents($filename.$suffix, $certificate, FILE_APPEND);
+
+ return $filename.$suffix;
+ }
+
+ private function getCrls(string $certificate): string
+ {
+ $parsed = openssl_x509_parse($certificate);
+ if (false === $parsed || !isset($parsed['extensions']['crlDistributionPoints'])) {
+ return '';
+ }
+ $endpoint = $parsed['extensions']['crlDistributionPoints'];
+ $pos = mb_strpos($endpoint, 'URI:');
+ if (!is_int($pos)) {
+ return '';
+ }
+
+ $endpoint = trim(mb_substr($endpoint, $pos + 4));
+ $request = $this->requestFactory->createRequest('GET', $endpoint);
+ $response = $this->client->sendRequest($request);
+
+ if (200 !== $response->getStatusCode()) {
+ return '';
+ }
+
+ return $response->getBody()->getContents();
+ }
+}