$max) { $theInt = $max; } return $theInt; } /** * Tests if the input can be interpreted as integer. * * Note: "0" will return true while any other number with a leading 0 (including multiple zeroes) will be false. * * Note: Integer casting from objects or arrays is considered undefined and thus will return false. * * @see https://php.net/manual/en/language.types.integer.php#language.types.integer.casting.from-other * @param mixed $var Any input variable to test * @return bool Returns TRUE if string is an integer */ public static function canBeInterpretedAsInteger(mixed $var): bool { return match (gettype($var)) { 'integer' => true, // Due to historical reasons `TRUE` is correctly interpreted as integer // but `FALSE` not even if a (int) cast would return `0` and keeping it // we can simply return the boolean value to have the same behaviour and // still avoiding type casting chain. 'boolean' => $var, // We use a type casting chain here to ensure that value is the same after // casting and eliminated invalid stuff from it. The `@` silence operator // can look weird here but is required to avoid enforced casting issues // with PHP 8.5.0 and newer. 'string' => (string)@(int)$var === $var, // We use a type casting chain here to ensure that value is the same after // casting and eliminated invalid stuff from it. The `@` silence operator // can look weird here but is required to avoid enforced casting issues // with PHP 8.5.0 and newer. // gettype() returns `double` for `float values` 'double' => !is_nan($var) && (string)@(int)$var === (string)$var, // non-scalar like array, object, resource, NULL or unknown_type default => false, }; } /** * Tests if the input can be interpreted as float. * * Note: Float casting from objects or arrays is considered undefined and thus will return false. * * @see http://www.php.net/manual/en/language.types.float.php, section "Formally" for the notation * @param mixed $var Any input variable to test * @return bool Returns TRUE if string is a float */ public static function canBeInterpretedAsFloat(mixed $var): bool { $pattern_lnum = '[0-9]+'; $pattern_dnum = '([0-9]*[\.]' . $pattern_lnum . ')|(' . $pattern_lnum . '[\.][0-9]*)'; $pattern_exp_dnum = '[+-]?((' . $pattern_lnum . '|' . $pattern_dnum . ')([eE][+-]?' . $pattern_lnum . ')?)'; if ($var === '' || is_object($var) || is_array($var)) { return false; } $matches = preg_match('/^' . $pattern_exp_dnum . '$/', (string)$var); return $matches === 1; } /** * Calculates the input by +,-,*,/,%,^ with priority to + and - * * @param string $string Input string, eg "123 + 456 / 789 - 4 * @return float|string Calculated value. Or error string. * @see \TYPO3\CMS\Core\Utility\MathUtility::calculateWithParentheses() */ public static function calculateWithPriorityToAdditionAndSubtraction(string $string): float|string { // Removing all whitespace $string = preg_replace('/[[:space:]]*/', '', $string); // Ensuring an operator for the first entrance $string = '+' . $string; $qm = '\\*\\/\\+-^%'; $regex = '([' . $qm . '])([' . $qm . ']?[0-9\\.]*)'; // Split the expression here: $reg = []; preg_match_all('/' . $regex . '/', $string, $reg); reset($reg[2]); $number = 0; $Msign = '+'; $err = ''; $buffer = (float)current($reg[2]); // Advance pointer $regSliced = array_slice($reg[2], 1, null, true); foreach ($regSliced as $k => $v) { $v = (float)$v; $sign = $reg[1][$k]; if ($sign === '+' || $sign === '-') { $Msign === '-' ? ($number -= $buffer) : ($number += $buffer); $Msign = $sign; $buffer = $v; } else { if ($sign === '/') { if ($v) { $buffer /= $v; } else { $err = 'dividing by zero'; } } if ($sign === '%') { if ($v) { $buffer %= $v; } else { $err = 'dividing by zero'; } } if ($sign === '*') { $buffer *= $v; } if ($sign === '^') { $buffer = $buffer ** $v; } } } $number = $Msign === '-' ? ($number - $buffer) : ($number + $buffer); return $err ? 'ERROR: ' . $err : $number; } /** * Calculates the input with parenthesis levels * * @param string $string Input string, eg "(123 + 456) / 789 - 4 * @return string Calculated value. Or error string. * @see calculateWithPriorityToAdditionAndSubtraction() * @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::stdWrap() */ public static function calculateWithParentheses(string $string): string { $securC = 100; do { $valueLenO = strcspn($string, '('); $valueLenC = strcspn($string, ')'); if ($valueLenC == strlen($string) || $valueLenC < $valueLenO) { $value = self::calculateWithPriorityToAdditionAndSubtraction(substr($string, 0, $valueLenC)); $string = $value . substr($string, $valueLenC + 1); return $string; } $string = substr($string, 0, $valueLenO) . self::calculateWithParentheses(substr($string, $valueLenO + 1)); // Security: $securC--; if ($securC <= 0) { break; } } while ($valueLenO < strlen($string)); return $string; } /** * Checks whether the given number $value is an integer in the range [$minimum;$maximum] * * @param mixed $value Integer value to check. If not an integer this method always returns false. * @param int $minimum Lower boundary of the range * @param int $maximum Upper boundary of the range */ public static function isIntegerInRange(mixed $value, int $minimum, int $maximum): bool { $value = filter_var($value, FILTER_VALIDATE_INT, [ 'options' => [ 'min_range' => $minimum, 'max_range' => $maximum, ], ]); return is_int($value); } }