1: <?php
2: /**
3: * Smarty plugin
4: * This plugin is only for Smarty2 BC
5: *
6: * @package Smarty
7: * @subpackage PluginsFunction
8: */
9: /**
10: * Smarty {math} function plugin
11: * Type: function
12: * Name: math
13: * Purpose: handle math computations in template
14: *
15: * @link http://www.smarty.net/manual/en/language.function.math.php {math}
16: * (Smarty online manual)
17: * @author Monte Ohrt <monte at ohrt dot com>
18: *
19: * @param array $params parameters
20: * @param Smarty_Internal_Template $template template object
21: *
22: * @return string|null
23: */
24: function smarty_function_math($params, $template)
25: {
26: static $_allowed_funcs =
27: array(
28: 'int' => true,
29: 'abs' => true,
30: 'ceil' => true,
31: 'acos' => true,
32: 'acosh' => true,
33: 'cos' => true,
34: 'cosh' => true,
35: 'deg2rad' => true,
36: 'rad2deg' => true,
37: 'exp' => true,
38: 'floor' => true,
39: 'log' => true,
40: 'log10' => true,
41: 'max' => true,
42: 'min' => true,
43: 'pi' => true,
44: 'pow' => true,
45: 'rand' => true,
46: 'round' => true,
47: 'asin' => true,
48: 'asinh' => true,
49: 'sin' => true,
50: 'sinh' => true,
51: 'sqrt' => true,
52: 'srand' => true,
53: 'atan' => true,
54: 'atanh' => true,
55: 'tan' => true,
56: 'tanh' => true
57: );
58:
59: // be sure equation parameter is present
60: if (empty($params[ 'equation' ])) {
61: trigger_error("math: missing equation parameter", E_USER_WARNING);
62: return;
63: }
64: $equation = $params[ 'equation' ];
65:
66: // Remove whitespaces
67: $equation = preg_replace('/\s+/', '', $equation);
68:
69: // Adapted from https://www.php.net/manual/en/function.eval.php#107377
70: $number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
71: $functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))';
72: $operators = '[,+\/*\^%-]'; // Allowed math operators
73: $regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)*\)|\((?1)*\)))(?:'.$operators.'(?1))?)+$/';
74:
75: if (!preg_match($regexp, $equation)) {
76: trigger_error("math: illegal characters", E_USER_WARNING);
77: return;
78: }
79:
80: // make sure parenthesis are balanced
81: if (substr_count($equation, '(') !== substr_count($equation, ')')) {
82: trigger_error("math: unbalanced parenthesis", E_USER_WARNING);
83: return;
84: }
85:
86: // disallow backticks
87: if (strpos($equation, '`') !== false) {
88: trigger_error("math: backtick character not allowed in equation", E_USER_WARNING);
89: return;
90: }
91:
92: // also disallow dollar signs
93: if (strpos($equation, '$') !== false) {
94: trigger_error("math: dollar signs not allowed in equation", E_USER_WARNING);
95: return;
96: }
97: foreach ($params as $key => $val) {
98: if ($key !== 'equation' && $key !== 'format' && $key !== 'assign') {
99: // make sure value is not empty
100: if (strlen($val) === 0) {
101: trigger_error("math: parameter '{$key}' is empty", E_USER_WARNING);
102: return;
103: }
104: if (!is_numeric($val)) {
105: trigger_error("math: parameter '{$key}' is not numeric", E_USER_WARNING);
106: return;
107: }
108: }
109: }
110: // match all vars in equation, make sure all are passed
111: preg_match_all('!(?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)!', $equation, $match);
112: foreach ($match[ 1 ] as $curr_var) {
113: if ($curr_var && !isset($params[ $curr_var ]) && !isset($_allowed_funcs[ $curr_var ])) {
114: trigger_error(
115: "math: function call '{$curr_var}' not allowed, or missing parameter '{$curr_var}'",
116: E_USER_WARNING
117: );
118: return;
119: }
120: }
121: foreach ($params as $key => $val) {
122: if ($key !== 'equation' && $key !== 'format' && $key !== 'assign') {
123: $equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation);
124: }
125: }
126: $smarty_math_result = null;
127: eval("\$smarty_math_result = " . $equation . ";");
128:
129: if (empty($params[ 'format' ])) {
130: if (empty($params[ 'assign' ])) {
131: return $smarty_math_result;
132: } else {
133: $template->assign($params[ 'assign' ], $smarty_math_result);
134: }
135: } else {
136: if (empty($params[ 'assign' ])) {
137: printf($params[ 'format' ], $smarty_math_result);
138: } else {
139: $template->assign($params[ 'assign' ], sprintf($params[ 'format' ], $smarty_math_result));
140: }
141: }
142: }
143: