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