2016-12-05 87 views
2

我必须建立一个计算一些数据的应用程序。我不知道科学家可以问什么计算。如何评估算术计算?

例如, 用户A将要计算(A + 5)* 3 用户B将要计算(A + 14)²* PI

的算术公式由科学家定义并存储在数据库由管理员。

最简单的方法就是做:

<?php 

    //Formula is initialized by a query in database 
    $formula= '(A + 3) * 5'; 
    //$ value is an integer entered by UserA and verify by Controller 
    $value = 42; 

    $arithmetic = str_replace('A', $formula, $value); 

    $result = eval($arithmetic); 

但因为它是由@thpl在此answer

解释评估和演示是邪恶的,我有两个选择:

  1. 要做好很多分析和转换公式的每个字符和 创建一个很好的计算类。 (发现 一个+和替换+字符的每个侧面的操作通过调用addition法等 等
  2. 检查$formula具有良好的(是否安全?)正则表达式,并调用邪恶eval功能。

第一个解决方案似乎更安全,但很长的发展

对于第二个方案,我发现这对PHP文档:

<?php 
    $test = '2+3*pi'; 

    // Remove whitespaces 
    $test = preg_replace('/\s+/', '', $test); 

    $number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number 
    $functions = '(?:sinh?|cosh?|tanh?|abs|acosh?|asinh?|atanh?|exp|log10|deg2rad|rad2deg|sqrt|ceil|floor|round)'; // Allowed PHP functions 
    $operators = '[+\/*\^%-]'; // Allowed math operators 
    $regexp = '/^((' . $number . '|' . $functions . '\s*\((?1)+\)|\((?1)+\))(?:' . $operators . '(?2))?)+$/'; // Final regexp, heavily using recursive patterns 

    if (preg_match($regexp, $q)) { 
     $test = preg_replace('!pi|π!', 'pi()', $test); // Replace pi with pi function 
     eval('$result = ' . $test . ';'); 
    } else { 
     $result = false; 
    } 

第一个问题:第二个解决方案是否足够安全?

我在互联网上搜索(当然),但找到的最好的解决方案是以前的代码。有一些PHP函数,珍珠或PECL库来帮助我吗?一个arithmetic_eval函数?

(我不Security.SE问,因为我的问题只涉及PHP)

回答

1

第一个解决方案(一个自定义的解析器),我会觉得很复杂,而且容易出错。其中最大的风险就是会允许攻击者运行任意代码的错误。也许你可以做对,但犯错很容易。

第二种解决方案(建议的基于正则表达式的验证)可以很好或不好,很难说。要花费大量的时间来分析PHP语法,将其与您问题中的正则表达式进行比较,查看PHP中用于编写语句和表达式的微妙方式等。乍一看,它看起来并不是灾难性的,没有人将能够说没有批次的分析是安全的。在那之前使用它是非常危险的。

您可能会决定接受其中之一的风险,因为您说这些公式将由管理员存储。管理员可以检查公式是否是似乎不包含任何代码的真正数学公式。尽管掩盖一些看起来像公式的细微代码执行可能并非不可能,但如果受信任的管理员在实际使用和评估之前审查所有内容,则风险要低得多。

让我提出一些不同的东西。如果你使用沙箱来评估表达式会怎么样?以this为例。您可以轻松地将可用于代码的功能限制为仅用于数学函数,只要您信任沙盒,您可以放心,不会有任何恶意行为发生。这会将问题转移给第三方(您必须相信,这是一个重要的决定!),并且您的代码将保持非常简单而合理的安全性。可能还有其他沙箱,您可能需要探索。