1<?php 2namespace TYPO3\CMS\Core\Utility; 3 4/* 5 * This file is part of the TYPO3 CMS project. 6 * 7 * It is free software; you can redistribute it and/or modify it under 8 * the terms of the GNU General Public License, either version 2 9 * of the License, or any later version. 10 * 11 * For the full copyright and license information, please read the 12 * LICENSE.txt file that was distributed with this source code. 13 * 14 * The TYPO3 project - inspiring people to share! 15 */ 16 17/** 18 * Class with helper functions for mathematical calculations 19 */ 20class MathUtility 21{ 22 /** 23 * Forces the integer $theInt into the boundaries of $min and $max. If the $theInt is FALSE then the $defaultValue is applied. 24 * 25 * @param int $theInt Input value 26 * @param int $min Lower limit 27 * @param int $max Higher limit 28 * @param int $defaultValue Default value if input is FALSE. 29 * @return int The input value forced into the boundaries of $min and $max 30 */ 31 public static function forceIntegerInRange($theInt, $min, $max = 2000000000, $defaultValue = 0) 32 { 33 // Returns $theInt as an integer in the integerspace from $min to $max 34 $theInt = (int)$theInt; 35 // If the input value is zero after being converted to integer, 36 // defaultValue may set another default value for it. 37 if ($defaultValue && !$theInt) { 38 $theInt = $defaultValue; 39 } 40 if ($theInt < $min) { 41 $theInt = $min; 42 } 43 if ($theInt > $max) { 44 $theInt = $max; 45 } 46 return $theInt; 47 } 48 49 /** 50 * Returns $theInt if it is greater than zero, otherwise returns zero. 51 * 52 * @param int $theInt Integer string to process 53 * @return int 54 */ 55 public static function convertToPositiveInteger($theInt) 56 { 57 $theInt = (int)$theInt; 58 if ($theInt < 0) { 59 $theInt = 0; 60 } 61 return $theInt; 62 } 63 64 /** 65 * Tests if the input can be interpreted as integer. 66 * 67 * Note: Integer casting from objects or arrays is considered undefined and thus will return false. 68 * 69 * @see http://php.net/manual/en/language.types.integer.php#language.types.integer.casting.from-other 70 * @param mixed $var Any input variable to test 71 * @return bool Returns TRUE if string is an integer 72 */ 73 public static function canBeInterpretedAsInteger($var) 74 { 75 if ($var === '' || is_object($var) || is_array($var)) { 76 return false; 77 } 78 return (string)(int)$var === (string)$var; 79 } 80 81 /** 82 * Tests if the input can be interpreted as float. 83 * 84 * Note: Float casting from objects or arrays is considered undefined and thus will return false. 85 * 86 * @see http://www.php.net/manual/en/language.types.float.php, section "Formally" for the notation 87 * @param mixed $var Any input variable to test 88 * @return bool Returns TRUE if string is a float 89 */ 90 public static function canBeInterpretedAsFloat($var) 91 { 92 $pattern_lnum = '[0-9]+'; 93 $pattern_dnum = '([0-9]*[\.]' . $pattern_lnum . ')|(' . $pattern_lnum . '[\.][0-9]*)'; 94 $pattern_exp_dnum = '[+-]?((' . $pattern_lnum . '|' . $pattern_dnum . ')([eE][+-]?' . $pattern_lnum . ')?)'; 95 96 if ($var === '' || is_object($var) || is_array($var)) { 97 return false; 98 } 99 100 $matches = preg_match('/^' . $pattern_exp_dnum . '$/', $var); 101 return $matches === 1; 102 } 103 104 /** 105 * Calculates the input by +,-,*,/,%,^ with priority to + and - 106 * 107 * @param string $string Input string, eg "123 + 456 / 789 - 4 108 * @return int Calculated value. Or error string. 109 * @see \TYPO3\CMS\Core\Utility\MathUtility::calculateWithParentheses() 110 */ 111 public static function calculateWithPriorityToAdditionAndSubtraction($string) 112 { 113 // Removing all whitespace 114 $string = preg_replace('/[[:space:]]*/', '', $string); 115 // Ensuring an operator for the first entrance 116 $string = '+' . $string; 117 $qm = '\\*\\/\\+-^%'; 118 $regex = '([' . $qm . '])([' . $qm . ']?[0-9\\.]*)'; 119 // Split the expression here: 120 $reg = []; 121 preg_match_all('/' . $regex . '/', $string, $reg); 122 reset($reg[2]); 123 $number = 0; 124 $Msign = '+'; 125 $err = ''; 126 $buffer = (float)current($reg[2]); 127 // Advance pointer 128 $regSliced = array_slice($reg[2], 1, null, true); 129 foreach ($regSliced as $k => $v) { 130 $v = (float)$v; 131 $sign = $reg[1][$k]; 132 if ($sign === '+' || $sign === '-') { 133 $Msign === '-' ? ($number -= $buffer) : ($number += $buffer); 134 $Msign = $sign; 135 $buffer = $v; 136 } else { 137 if ($sign === '/') { 138 if ($v) { 139 $buffer /= $v; 140 } else { 141 $err = 'dividing by zero'; 142 } 143 } 144 if ($sign === '%') { 145 if ($v) { 146 $buffer %= $v; 147 } else { 148 $err = 'dividing by zero'; 149 } 150 } 151 if ($sign === '*') { 152 $buffer *= $v; 153 } 154 if ($sign === '^') { 155 $buffer = pow($buffer, $v); 156 } 157 } 158 } 159 $number = $Msign === '-' ? ($number -= $buffer) : ($number += $buffer); 160 return $err ? 'ERROR: ' . $err : $number; 161 } 162 163 /** 164 * Calculates the input with parenthesis levels 165 * 166 * @param string $string Input string, eg "(123 + 456) / 789 - 4 167 * @return int Calculated value. Or error string. 168 * @see calculateWithPriorityToAdditionAndSubtraction(), \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::stdWrap() 169 */ 170 public static function calculateWithParentheses($string) 171 { 172 $securC = 100; 173 do { 174 $valueLenO = strcspn($string, '('); 175 $valueLenC = strcspn($string, ')'); 176 if ($valueLenC == strlen($string) || $valueLenC < $valueLenO) { 177 $value = self::calculateWithPriorityToAdditionAndSubtraction(substr($string, 0, $valueLenC)); 178 $string = $value . substr($string, $valueLenC + 1); 179 return $string; 180 } 181 $string = substr($string, 0, $valueLenO) . self::calculateWithParentheses(substr($string, $valueLenO + 1)); 182 183 // Security: 184 $securC--; 185 if ($securC <= 0) { 186 break; 187 } 188 } while ($valueLenO < strlen($string)); 189 return $string; 190 } 191 192 /** 193 * Checks whether the given number $value is an integer in the range [$minimum;$maximum] 194 * 195 * @param int $value Integer value to check 196 * @param int $minimum Lower boundary of the range 197 * @param int $maximum Upper boundary of the range 198 * @return bool 199 */ 200 public static function isIntegerInRange($value, $minimum, $maximum) 201 { 202 $value = filter_var($value, FILTER_VALIDATE_INT, [ 203 'options' => [ 204 'min_range' => $minimum, 205 'max_range' => $maximum 206 ] 207 ]); 208 $isInRange = is_int($value); 209 return $isInRange; 210 } 211} 212