2016-12-05 5 views
2

Мне нужно создать приложение, которое вычисляет некоторые данные. Я не знаю, какие вычисления могут потребовать ученые.Как оценивать арифметические вычисления?

Например, Пользователь A будет необходимо вычислить (А + 5) * 3 пользователя Б захочет, чтобы вычислить (А + 14) ² * пи

арифметики формула определяется учеными и хранится в базы данных от администратора.

Простой способ это сделать:

<?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); 

Но Eval зло, как это объясняется @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-функции, библиотеки pearl или PECL, чтобы помочь мне? функция arithmetic_eval?

(я не прошу в Security.SE, потому что мой вопрос касается только PHP)

ответ

1

Первое решение (пользовательский анализатор) бы я думаю, будет очень сложным и подверженным ошибкам. Наибольший риск в этом случае будет ошибкой, которая все равно позволит злоумышленнику запустить произвольный код. Возможно, вы можете это исправить, но легко ошибаться.

Второе решение (предлагаемое подтверждение на основе регулярных выражений) может быть хорошим или нет, трудно сказать. Это займет много времени, чтобы проанализировать синтаксис PHP, сравнить его с регулярными выражениями в вашем вопросе, посмотреть, какие тонкие способы есть в PHP для написания операторов и выражений и т. Д. На первый взгляд это не выглядит катастрофическим, никто сможет сказать, что это безопасно без лотов анализа. Было бы очень рискованно использовать его до тех пор.

Вы можете принять риск любого из них, потому что вы говорите, что эти формулы будут храниться администраторами. Админы могут проверить, являются ли формулы настоящими математическими формулами, которые, как представляется, не содержат никакого кода. Хотя, вероятно, не невозможно замаскировать тонкое выполнение кода в материалах, которые выглядят как формула, риск намного ниже, если доверенный администратор проверяет все до того, как он фактически используется и оценивается.

Позвольте мне предложить что-то другое, хотя. Что делать, если вы использовали песочницу для оценки выражений? Посмотрите, например, на this. Вы можете легко ограничить функции, доступные для кода, только математическим функциям, и до тех пор, пока вы доверяете песочнице, вы можете быть уверены, что ничего не будет запущено. Это вывело бы проблему третьей стороне (которой вы должны доверять, это важное решение!), И ваш код останется очень простым, но достаточно безопасным. Могут быть и другие песочницы, которые вы можете изучить.