PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / V3.3.2
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder vV3.3.2
V3.3.2 3.3.1 V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 All 139 releases
← All changes | includes/Core/WorkFlow/Helper.php +96 -24 3.2.0 → V3.3.2 View file →
@@ -21,8 +21,12 @@
21 21 'key' => $fieldKey,
22 22 'value' => $value,
23 23 'type' => $fieldDetail->typ,
24 24 ];
25 + if ('advanced-datetime' === $fieldData[$fieldKey]['type']) {
26 + // Date conditions must parse the posted value in the field's own format.
27 + $fieldData[$fieldKey]['dateFormat'] = DateConditionComparator::advancedValueFormat(isset($fieldDetail->config) ? $fieldDetail->config : null);
28 + }
25 29 if (isset($fieldDetail->mul)) {
26 30 $fieldData[$fieldKey] =
27 31 array_merge(
28 32 $fieldData[$fieldKey],
@@ -30,8 +34,13 @@
30 34 'mul' => $fieldDetail->mul,
31 35 ]
32 36 );
33 37 }
38 + // A multiple-choice Image Select holds a list, like a checkbox; compared as one string
39 + // only its last choice counted.
40 + if ('image-select' === $fieldDetail->typ && isset($fieldDetail->inpType) && 'checkbox' === $fieldDetail->inpType) {
41 + $fieldData[$fieldKey]['mul'] = true;
42 + }
34 43 }
35 44 return $fieldData;
36 45 }
37 46
@@ -88,9 +97,16 @@
88 97 || isset($conditionalActionIds['successMsg'][(string) $msg->id])
89 98 ) {
90 99 continue;
91 100 }
92 - $returnableData = self::replaceFieldWithValue($msg->message_content, $fieldValue, true, null, true);
101 + // Translate before smart-tag replacement (identity when unhooked).
102 + $messageContent = (string) apply_filters(
103 + 'bitform_translate_form_string',
104 + (string) $msg->message_content,
105 + 'msg-content-' . $msg->id,
106 + $formId
107 + );
108 + $returnableData = self::replaceFieldWithValue($messageContent, $fieldValue, true, null, true);
93 109 $messageId = $msg->id;
94 110 if (isset($msgConfig->afterSubmit)) {
95 111 $afterSubmit = $msgConfig->afterSubmit;
96 112 }
@@ -109,8 +125,15 @@
109 125 continue;
110 126 }
111 127 $url = Utilities::jsonObj($redirectPage->integration_details ?? '')->url ?? '';
112 128 if (!empty($url)) {
129 + // Translated before smart-tag replacement: per-language redirect targets.
130 + $url = (string) apply_filters(
131 + 'bitform_translate_form_string',
132 + (string) $url,
133 + 'redirect-url-' . $redirectPage->id,
134 + $formId
135 + );
113 136 $url = self::replaceFieldWithValue($url, $fieldValue);
114 137 }
115 138 $returnableData = empty($url) ? '' : esc_url_raw($url);
116 139 break;
@@ -304,22 +327,15 @@
304 327 }
305 328 return $ids;
306 329 }
307 330
331 + /**
332 + * @deprecated misspelled duplicate of calculate(); kept because it is public API. Same
333 + * divide-by-zero guard so an external caller cannot fatal either.
334 + */
308 335 public static function calculte($firstOperand, $secondOperand, $operator)
309 336 {
310 - switch ($operator) {
311 - case '+':
312 - return $firstOperand + $secondOperand;
313 - case '-':
314 - return $firstOperand - $secondOperand;
315 - case '*':
316 - return $firstOperand * $secondOperand;
317 - case '/':
318 - return $firstOperand / $secondOperand;
319 - case '^':
320 - return $firstOperand ** $secondOperand;
321 - }
337 + return self::calculate($firstOperand, $secondOperand, $operator);
322 338 }
323 339
324 340 public static function filterMailContentType()
325 341 {
@@ -328,11 +344,26 @@
328 344
329 345 public static function evalMathExpression($stringWithFieldValue)
330 346 {
331 347 $mathExpr = $stringWithFieldValue;
332 - if (empty($mathExpr)) {
348 + if (empty($mathExpr) || !\is_scalar($mathExpr)) {
333 349 return $stringWithFieldValue;
334 350 }
351 + $mathExpr = (string) $mathExpr;
352 +
353 + // The operand/operator checks below only look at \w+ runs and operator runs, so any other
354 + // character was invisible to them. A quoted date ('2020-10-10') therefore passed as a
355 + // subtraction chain and its quotes later surfaced as a bogus operator token. Require the whole
356 + // string to be made of things a formula can contain.
357 + if (1 !== preg_match('#^[0-9.+\-*/^()\[\]{}\s]+$#', $mathExpr)) {
358 + return $stringWithFieldValue;
359 + }
360 +
361 + // A bare date is not a subtraction: 2020-10-10 must stay a date, not become 2000.
362 + if (1 === preg_match('/^\s*\d{4}-\d{1,2}-\d{1,2}\s*$/', $mathExpr)) {
363 + return $stringWithFieldValue;
364 + }
365 +
335 366 preg_match_all('/[\+\-\*\/\s]+/', $mathExpr, $isMathExpr);
336 367 if (empty($isMathExpr[0])) {
337 368 return $stringWithFieldValue;
338 369 }
@@ -354,9 +385,9 @@
354 385 $mathExpr = str_replace(' ', '', $mathExpr);
355 386 $mathExpr = preg_replace('/\{|\[|\(/', '(', $mathExpr);
356 387 $mathExpr = preg_replace('/\}|\]/', ')', $mathExpr);
357 388 $calculated = self::infixToPostfixEvalute($mathExpr);
358 - if (!is_null($calculated)) {
389 + if (!is_null($calculated) && isset($calculated[0])) {
359 390 return (string) $calculated[0];
360 391 }
361 392
362 393 return (string) $stringWithFieldValue;
@@ -380,10 +411,18 @@
380 411 }
381 412 if ('(' === $token) {
382 413 $operatorStack[] = $token;
383 414 } elseif (')' === $token) {
415 + // An unbalanced ')' used to read $operatorStack[-1] and warn on every iteration; treat
416 + // the expression as non-arithmetic instead.
417 + if (empty($operatorStack)) {
418 + return null;
419 + }
384 420 while ('(' !== $operatorStack[count($operatorStack) - 1]) {
385 421 $outputQueue[] = array_pop($operatorStack);
422 + if (empty($operatorStack)) {
423 + return null;
424 + }
386 425 if ('(' === $operatorStack[count($operatorStack) - 1]) {
387 426 array_pop($operatorStack);
388 427 break;
389 428 }
@@ -412,11 +451,22 @@
412 451 if (is_numeric($value)) {
413 452 $resultStack[] = $value;
414 453 continue;
415 454 }
455 + // A token that is neither a number nor a real operator means the input was never an
456 + // expression — e.g. a quoted date whose quotes accumulated into a token like "'2020".
457 + // Bail out so evalMathExpression() returns the caller's string untouched; pushing the
458 + // failure onto the stack would end up blanking that string.
459 + if (!\in_array($value, ['+', '-', '*', '/', '^'], true) || count($resultStack) < 2) {
460 + return null;
461 + }
416 462 $secondOperand = array_pop($resultStack);
417 463 $firstOperand = array_pop($resultStack);
418 - $resultStack[] = self::calculate($firstOperand, $secondOperand, $value);
464 + $calculated = self::calculate($firstOperand, $secondOperand, $value);
465 + if (\is_null($calculated)) {
466 + return null;
467 + }
468 + $resultStack[] = $calculated;
419 469 }
420 470 return $resultStack;
421 471 }
422 472
@@ -432,19 +482,41 @@
432 482
433 483 return isset($precedence[$operator]) ? $precedence[$operator] : 0;
434 484 }
435 485
486 + /**
487 + * Apply one arithmetic operator.
488 + *
489 + * @param mixed $firstOperand
490 + * @param mixed $secondOperand
491 + * @param string $operator
492 + *
493 + * @return float|int|null null on unknown operator, non-numeric operand, or division by zero
494 + */
436 495 public static function calculate($firstOperand, $secondOperand, $operator)
437 496 {
438 - $calculated = [
439 - '+' => $firstOperand + $secondOperand,
440 - '-' => $firstOperand - $secondOperand,
441 - '*' => $firstOperand * $secondOperand,
442 - '/' => $firstOperand / $secondOperand,
443 - '^' => $firstOperand ** $secondOperand,
444 - ];
497 + if (!is_numeric($firstOperand) || !is_numeric($secondOperand)) {
498 + return null;
499 + }
500 + $firstOperand = $firstOperand + 0;
501 + $secondOperand = $secondOperand + 0;
445 502
446 - return isset($calculated[$operator]) ? $calculated[$operator] : '';
503 + switch ($operator) {
504 + case '+':
505 + return $firstOperand + $secondOperand;
506 + case '-':
507 + return $firstOperand - $secondOperand;
508 + case '*':
509 + return $firstOperand * $secondOperand;
510 + case '/':
511 + // Compare as float, not with `0 ==`: PHP 8 made `0 == ''` false, so a
512 + // non-numeric operand slipped past the old guard into DivisionByZeroError.
513 + return 0.0 === (float) $secondOperand ? null : $firstOperand / $secondOperand;
514 + case '^':
515 + return $firstOperand ** $secondOperand;
516 + }
517 +
518 + return null;
447 519 }
448 520
449 521 /**
450 522 * Recursively sets a nested property in a given object.