PluginProbe
E2Pdf – Export Pdf Tool for WordPress / 1.32.49
E2Pdf – Export Pdf Tool for WordPress v1.32.49
1.32.49 1.32.48 1.32.43 1.32.40 1.32.34 1.32.32 1.32.31 1.32.26 1.32.22 1.32.23 1.32.18 1.32.17 1.32.15 trunk 1.00.00 1.00.13 1.01.01 1.02.02 1.03.07 1.04.07 1.05.03 1.06.02 1.07.11 1.08.00 1.08.06 All 72 releases
e2pdf / classes / helper / e2pdf-math.php

e2pdf-math.php in E2Pdf – Export Pdf Tool for WordPress 1.32.49, at classes/helper/e2pdf-math.php

323 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * File: /helper/e2pdf-math.php
5 *
6 * @package E2Pdf
7 * @license GPLv3
8 * @link https://e2pdf.com
9 */
10 if (!defined('ABSPATH')) {
11 die('Access denied.');
12 }
13
14 /** @license
15 * Based on https://gist.github.com/ircmaxell/1232629
16 */
17 class Helper_E2pdf_Math {
18
19 private $helper;
20 protected $variables = [];
21 protected $stack = [];
22 protected $output = [];
23
24 public function __construct() {
25 $this->helper = Helper_E2pdf_Helper::instance();
26 }
27
28 public function pre_render($value = '', $extension = null) {
29 $replacements = [];
30 if ($value) {
31 preg_match_all('@\[([^<>&/\[\]\x00-\x20=]++)@', $value, $matches);
32 $tagnames = $matches[1];
33 if (!empty($tagnames)) {
34 preg_match_all('/' . $this->helper->load('shortcode')->get_shortcode_regex($tagnames) . '/', $value, $shortcodes);
35 foreach ($shortcodes[0] as $key => $shortcode_value) {
36 $index = count($replacements) + 1;
37 $replacements[] = $shortcode_value;
38 $value = str_replace($shortcode_value, '%' . $index . '$s', $value);
39 }
40 }
41
42 if (method_exists($extension, 'strip_math')) {
43 $value = $extension->strip_math($value, $replacements);
44 }
45
46 if (!empty($replacements)) {
47 $value = preg_replace('/%(?!\d+\$s)/', '%%', $value);
48 $value = vsprintf(
49 $value, array_map(
50 function ($v) {
51 return '(' . $v . ')';
52 }, $replacements
53 )
54 );
55 }
56 }
57 return $value;
58 }
59
60 public function after_render($value) {
61 return str_replace('()', '0', $value);
62 }
63
64 public function evaluate($string) {
65 try {
66 $this->stack = $this->parse($string);
67 return $this->run();
68 } catch (Exception $ex) {
69 return $ex->getMessage();
70 }
71 }
72
73 public function parse($string) {
74 $tokens = $this->tokenize(str_replace(' ', '', $string));
75 $this->output = [];
76 $this->operators = [];
77 foreach ($tokens as $token) {
78 $token = $this->extractVariables($token);
79 $expression = $this->factory($token);
80 if ($expression->operator) {
81 $this->parseOperator($expression);
82 } elseif (isset($expression->type) && $expression->type == 'parenthesis') {
83 $this->parseParenthesis($expression);
84 } else {
85 $this->output[] = $expression;
86 }
87 }
88 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
89 while (($op = array_pop($this->operators))) {
90 if (isset($op->type) && $op->type == 'parenthesis') {
91 throw new Exception(__('Mismatched Parenthesis in Math operation', 'e2pdf'));
92 }
93 $this->output[] = $op;
94 }
95 return $this->output;
96 }
97
98 public function registerVariable($name, $value) {
99 $this->variables[$name] = $value;
100 }
101
102 public function run() {
103 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
104 while (($operator = array_pop($this->stack)) && $operator->operator) {
105 $value = $this->operate($operator);
106 if (!is_null($value)) {
107 $this->stack[] = $this->factory($value);
108 }
109 }
110 return $operator ? $operator->value : $this->render();
111 }
112
113 protected function extractVariables($token) {
114 if ($token[0] == '$') {
115 $key = substr($token, 1);
116 return isset($this->variables[$key]) ? $this->variables[$key] : 0;
117 }
118 return $token;
119 }
120
121 protected function render() {
122 $output = '';
123 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
124 while (($el = array_pop($this->stack))) {
125 $output .= $el->value;
126 }
127 if ($output) {
128 return $output;
129 }
130 throw new Exception(__('Could not parse Math operation', 'e2pdf'));
131 }
132
133 protected function parseParenthesis($expression) {
134 if ($expression->open) {
135 $this->operators[] = $expression;
136 } else {
137 $clean = false;
138 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
139 while (($end = array_pop($this->operators))) {
140 if (isset($end->type) && $end->type == 'parenthesis') {
141 $clean = true;
142 break;
143 } else {
144 $this->output[] = $end;
145 }
146 }
147 if (!$clean) {
148 throw new Exception(__('Mismatched Parenthesis in Math operation', 'e2pdf'));
149 }
150 }
151 }
152
153 protected function parseOperator($expression) {
154 $end = end($this->operators);
155 if (!$end) {
156 $this->operators[] = $expression;
157 } elseif ($end->operator) {
158 do {
159 if ($expression->operator && $expression->precidence <= $end->precidence) {
160 $this->output[] = array_pop($this->operators);
161 } elseif (!$expression->operator && $expression->precidence < $end->precidence) {
162 $this->output[] = array_pop($this->operators);
163 } else {
164 break;
165 }
166 } while (($end = end($this->operators)) && $end->operator); // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
167
168 $this->operators[] = $expression;
169 } else {
170 $this->operators[] = $expression;
171 }
172 }
173
174 protected function tokenize($string) {
175 $parts = preg_split('((\b\d[\d.]*\b|\+|-|\(|\)|\*|\^|¦|/)|\s+)', $string, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
176 $parts = array_map('trim', $parts);
177
178 $tokens = [];
179 $expectOperand = true;
180
181 $count = count($parts);
182 for ($i = 0; $i < $count; $i++) {
183 $token = $parts[$i];
184 if (($token === '+' || $token === '-') && $expectOperand) {
185 $sign = 1;
186 while ($i < $count && ($parts[$i] === '+' || $parts[$i] === '-')) {
187 if ($parts[$i] === '-') {
188 $sign *= -1;
189 }
190 $i++;
191 }
192 if ($i >= $count || $parts[$i] === ')') {
193 if (!empty($tokens)) {
194 $last = end($tokens);
195 if (in_array($last, ['+', '-', '*', '/', '^', '¦'], true)) {
196 array_pop($tokens);
197 }
198 }
199 if ($i < $count) {
200 $i--;
201 }
202 $expectOperand = false;
203 continue;
204 }
205 $next = $parts[$i];
206 if (is_numeric($next)) {
207 $tokens[] = ($sign === -1) ? (string) (-1 * floatval($next)) : $next;
208 $expectOperand = false;
209 } elseif ($next === '(') {
210 if ($sign === -1) {
211 $tokens[] = '-1';
212 $tokens[] = '*';
213 }
214 $tokens[] = '(';
215 $expectOperand = true;
216 } else {
217 $tokens[] = $next;
218 $expectOperand = false;
219 }
220 } elseif ($token === '(') {
221 $tokens[] = $token;
222 $expectOperand = true;
223 } elseif ($token === ')') {
224 $tokens[] = $token;
225 $expectOperand = false;
226 } elseif (in_array($token, ['+', '-', '*', '/', '^', '¦'], true)) {
227 $tokens[] = $token;
228 $expectOperand = true;
229 } else {
230 $tokens[] = $token;
231 $expectOperand = false;
232 }
233 }
234 return $tokens;
235 }
236
237 protected function factory($value) {
238 $expression = new stdClass();
239 $expression->open = false;
240 $expression->operator = false;
241 $expression->precidence = 0;
242 $expression->type = 'expression';
243 if (is_object($value)) {
244 return $value;
245 } elseif (is_numeric($value)) {
246 $expression->type = 'number';
247 } elseif ($value == '+') {
248 $expression->operator = true;
249 $expression->type = 'addition';
250 $expression->precidence = 4;
251 } elseif ($value == '-') {
252 $expression->operator = true;
253 $expression->type = 'subtraction';
254 $expression->precidence = 4;
255 } elseif ($value == '*') {
256 $expression->operator = true;
257 $expression->type = 'multiplication';
258 $expression->precidence = 5;
259 } elseif ($value === '¦') {
260 $expression->operator = true;
261 $expression->type = 'modulus';
262 $expression->precidence = 5;
263 } elseif ($value == '/') {
264 $expression->operator = true;
265 $expression->type = 'division';
266 $expression->precidence = 5;
267 } elseif ($value == '^') {
268 $expression->operator = true;
269 $expression->type = 'power';
270 $expression->precidence = 6;
271 } elseif (in_array($value, ['(', ')'], true)) {
272 $expression->type = 'parenthesis';
273 $expression->precidence = 7;
274 $expression->open = $value == '(';
275 } else {
276 $value = 0;
277 $expression->type = 'number';
278 }
279 $expression->value = $value;
280 return $expression;
281 }
282
283 protected function operate($expression) {
284 $value = null;
285 if (isset($expression->type)) {
286 switch ($expression->type) {
287 case 'number':
288 $value = $expression->value;
289 break;
290 case 'addition':
291 $value = $this->operate(array_pop($this->stack)) + $this->operate(array_pop($this->stack));
292 break;
293 case 'subtraction':
294 $left = $this->operate(array_pop($this->stack));
295 $right = $this->operate(array_pop($this->stack));
296 $value = $right - $left;
297 break;
298 case 'multiplication':
299 $value = $this->operate(array_pop($this->stack)) * $this->operate(array_pop($this->stack));
300 break;
301 case 'division':
302 $left = $this->operate(array_pop($this->stack));
303 $right = $this->operate(array_pop($this->stack));
304 $value = ($left == 0) ? 0 : $right / $left;
305 break;
306 case 'power':
307 $left = $this->operate(array_pop($this->stack));
308 $right = $this->operate(array_pop($this->stack));
309 $value = pow($right, $left);
310 break;
311 case 'modulus':
312 $left = $this->operate(array_pop($this->stack));
313 $right = $this->operate(array_pop($this->stack));
314 $value = ($left == 0) ? 0 : ($right % $left);
315 break;
316 default:
317 break;
318 }
319 }
320 return $value;
321 }
322 }
323