diff --git a/.travis.yml b/.travis.yml index 0979abe3e..669743f97 100755 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,10 @@ env: matrix: include: + - php: 7.3 + env: WP_VERSION=latest TEST_JS=yes + - php: 7.2 + env: WP_VERSION=latest TEST_JS=yes - php: 7.1 env: WP_VERSION=trunk TEST_JS=yes - php: 7.1 @@ -43,7 +47,26 @@ before_script: - | if [[ ! -z "$WP_VERSION" ]] ; then bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION - composer global require "phpunit/phpunit=4.8.*|5.7.*" + if [[ "$WP_TRAVISCI" == "travis:phpunit" ]]; then + case "$TRAVIS_PHP_VERSION" in + 7.4snapshot|7.3|7.2|7.1|nightly) + echo "Using PHPUnit 7.x" + travis_retry composer global require "phpunit/phpunit:^7" + ;; + 7.0) + echo "Using PHPUnit 6.x" + travis_retry composer global require "phpunit/phpunit:^6" + ;; + 5.6) + echo "Using PHPUnit 4.x" + travis_retry composer global require "phpunit/phpunit:^4" + ;; + *) + echo "No PHPUnit version handling for PHP version $TRAVIS_PHP_VERSION" + exit 1 + ;; + esac + fi fi - | if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then diff --git a/classes/core.php b/classes/core.php index d88581ba0..fc1f53899 100755 --- a/classes/core.php +++ b/classes/core.php @@ -18,6 +18,8 @@ * */ +use FormulaParser\FormulaParser; + class Caldera_Forms { @@ -1390,6 +1392,92 @@ static public function akismet_scanner($config, $form) } + /** + * Catch known functions that were supported at https://calderaforms.com/doc/calculation-fields/ and are not sipported by parser https://github.com/denissimon/formula-parser + * + * @since 1.8.5 + * + * @param string $formula The string used to evaluate the math formula + * + * @return bool||string of coma seperated deprecated symbol + */ + static public function check_deprecated_math_functions($formula) + { + //List known depracated functions + $deprecated = array( ',', '**', 'pow', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'floor', 'max', 'min', 'random', 'round'); + //Look for matching known symbol in formula and push it in a symbols array + foreach ($deprecated as $symbol) { + if (strpos($formula, $symbol) !== FALSE) { + $symbols[] = $symbol; + } + } + //If symbols array is not empty convert it to a string and return the string + if(is_array($symbols) && !empty($symbols)){ + $symbols = implode( ',', $symbols); + return $symbols; + } else { + //Else return false + return false; + } + + } + + /** + * Calculation based on create_function() ( deprecated since PHP 7.2.0 ) + * + * @since 1.8.5 + * + * @param string $formula that needs to be parsed and processed as a calculation + * + * @return result of calculation + */ + static public function original_calculation_job( $formula ) + { + $total_function = create_function(null, 'return ' . $formula . ';'); + $total = $total_function(); + + return $total; + } + + /** + * Process when php >= 7.2.0 and deprecated is caught + * + * @since 1.8.5 + * + * @param string $formula to be sent to original calculation job + * @param string $deprecated function or symbol caught + * + * @return original process and notice for admin users + */ + static public function calculation_deprecated_caught_process( $formula, $deprecated ) + { + if( current_user_can( Caldera_Forms::get_manage_cap('admin') ) ) { + + $message = sprintf( + '"%s" %s', + $deprecated, + __('has been deprecated in calculation fields for compatibility with PHP 7.2 or later', 'caldera-forms') + ); + + /** + * The notice currentl only works whe ajax is enabled + * + * TODO Add notice for non ajax submissions + */ + add_filter('caldera_forms_render_notices', function( $out ) use ( $message ){ + + //Add an error notice holding the $message + $out[ 'error' ][ 'note' ] = $message; + + return $out; + + }, 25); + + } + + return self::original_calculation_job($formula); + } + /** * Process a calculation field. * @@ -1447,9 +1535,37 @@ static public function run_calculation($value, $field, $form) return new WP_Error($field['ID'] . '-calculation', __('Calculation is invalid (division by zero)', 'caldera-forms')); } + + //If PHP version is less than 7.2.0, continue using old function + if(version_compare(PHP_VERSION, '7.2.0', '<')){ + + $total = self::original_calculation_job($formula); + + } else { + //else avoid using create_function() when using PHP version >= 7.2.0 + + //Check if the formula use a symbol or function not supported by the parser but declared as supported at https://calderaforms.com/doc/calculation-fields/ + $deprecated = self::check_deprecated_math_functions( $formula ); + + //Use parser if no deprecated caught + if( $deprecated === false ){ + //Initiate parser + $parser = new FormulaParser($formula); + $result = $parser->getResult(); + //Get result if parser returns a correct status + if($result[0] === "done"){ + $total = $result['1']; + } else if($result[0] === "error") { + //else change notice for admins and run original process + $total = self::calculation_deprecated_caught_process( $formula, __('This formula', 'caldera_forms') ); + } + + } else { + //else change notice for admins and run original process + $total = self::calculation_deprecated_caught_process( $formula, $deprecated ); + } - $total_function = create_function(null, 'return ' . $formula . ';'); - $total = $total_function(); + } if (is_infinite($total) || !is_numeric($total)) { return new WP_Error($field['ID'] . '-calculation', __('Calculation is invalid', 'caldera-forms')); diff --git a/composer.json b/composer.json index 5baa2c1f9..48fd270ea 100755 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "calderawp/caldera-containers": "^0.2.0", "composer/installers": "^1.6", "a5hleyrich/wp-queue": "^1.3", - "symfony/translation": "~3.0" + "symfony/translation": "~3.0", + "denissimon/formula-parser": "^2.5" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index d47b6d6da..a9fde11ab 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0ff93cc09453663b555fc6e87714f122", + "content-hash": "50344505d8a9f8d074ad26c467be6635", "packages": [ { "name": "a5hleyrich/wp-queue", @@ -273,6 +273,50 @@ ], "time": "2018-08-27T06:10:37+00:00" }, + { + "name": "denissimon/formula-parser", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/denissimon/formula-parser.git", + "reference": "12ea2490d2bd0cd5feabdf03ee29dcba419c08d6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/denissimon/formula-parser/zipball/12ea2490d2bd0cd5feabdf03ee29dcba419c08d6", + "reference": "12ea2490d2bd0cd5feabdf03ee29dcba419c08d6", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "FormulaParser\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Denis Simon", + "email": "denis.v.simon@gmail.com", + "role": "Developer" + } + ], + "description": "Parsing and evaluating mathematical formulas given as strings.", + "keywords": [ + "expression", + "formula", + "math", + "parser", + "parsing" + ], + "time": "2016-12-28T19:36:53+00:00" + }, { "name": "inpsyde/wonolog", "version": "1.0.2",