2016-12-05 88 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爲例。您可以輕鬆地將可用於代碼的功能限制爲僅用於數學函數,只要您信任沙盒,您可以放心,不會有任何惡意行爲發生。這會將問題轉移給第三方(您必須相信,這是一個重要的決定!),並且您的代碼將保持非常簡單而合理的安全性。可能還有其他沙箱,您可能需要探索。