Подстановка значений в математическую операцию из базы MySQL

BSB

Новичок
Здравствуйте, уважаемое сообщество!
Логический тупик у меня произошел из-за нехватки знаний, прошу помощи.
Необходимо дать возможность пользователю составить условия математической операции с неограниченным количеством значений выбираемых из БД MySQL полей.
То есть, вычисления вида
Код:
(x+y)/z-w... и т.д.
в том порядке, как укажет пользователь.
При этом в качестве неизвестных он вправе выбрать значения параметра из определенной таблицы MySQL. Необходимую формулу вычисления нужно сохранить в другой таблице, чтобы затем обращаться к ней в момент вывода отчета.
Как это можно осуществить?
Технически я начал с того, что даю пользователю заполнить HTML-список из таблицы (вид таблицы "key=>value").
И завис...
 

Hello

Новичок
Сохранять формулу в обратной польской нотации, но вместо чисел использовать уникальный символ (к примеру @).
 

ksnk

прохожий
а почему в обратной польской?
Вероятно, чтобы самому возится вычислять. Приоритеты операций, реализация математических функций на коленке, романтика...
А вот create_function, eval или сгенерировать отдельный php-файл с формулой - это слишком просто ;)
 

WMix

герр M:)ller
Партнер клуба
дык куча калькуляторов и с парсингом (не eval) тоже, бери и пользуй
 

ksnk

прохожий
@BSB, Нужно бы объяснить, зачем и куда такие формулы будут использоваться.

вот решение, которое кажется мне наиболее компактным - не требующим много букв.
сначала - соглашения.
Формула обязана следовать соглашениям php о записи математических выражений, формула может использовать математические функции в том виде, как это может быть записано в php.
Имена переменных обязаны быть характерными и понятными для выковыривания их регуляркой из формулы. Например - все идентификаторы, за которыми не идет открывающая скобка.
PHP:
$x='(x1+y)/z+max(a,b)-w';
preg_match_all('/([a-z]\w*)[^\w\(]/i',$x,$m);
Вот такая регулярка достанет все 5 переменных из выражения. При некотором навыке - можно доработать ее, чтобы она не спотыкалась на вещественных с E.
С самой формулой производятся танцы. Все переменные заменяются (той же регуляркой) на переменные с $ вначале и сама формула дописывается в файл equation.php такого, к примеру, вида
PHP:
<?php
return [
'(x1+y)/z+max(a,b)-w'=>function ($x1,$y,$z,$a,$b) { return  ($x1+$y)/$z+max($a,$b)-$w;},
'2+2==5'=>function () { return  2+2==5;},
];
Основной косяк - понять, что получившийся файл синтаксически верный. Это можно узнать, выполнив `php -t equation.php` и посмотрев что и как возвращается. Второй этап - подставить переменные и выполнить эту формулу. Тут уже достаточно аккуратно окружить выполнение формулы обработчиками ошибок и исключений.
Риск - генерация кода на лету, можно получить синтаксически неверную конструкцию, с которой php просто грохнется.
Зато само вычисление по формуле получается быстрым. Если формулу использовать для графиков или сложных вычислений - скорости калькулятора с парсером может и не хватить.
 

WMix

герр M:)ller
Партнер клуба
риск получить иньекцию в первую очередь, функции только через белый список
 

ksnk

прохожий
риск получить иньекцию в первую очередь
Это да. Если разрешать ввод формулы всем подряд, а не специально обученным админам, перебрать формулу парсером - будет, конечно, правильнее. И синтаксис проверять дополнительно уже не надо.
С другой стороны, иньекции можно исключить, если не позволять юзеру использовать переменные, начинающиеся с $. Вообще говоря, для такой схемы генерации - в теле функции, достаточно проверить использование суперглобальных.
Ну и строковые операции тоже нужно исключить, во избежание неожиданных привидений с моторчиком...
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Вообще говоря, для такой схемы генерации - в теле функции, достаточно проверить использование суперглобальных.
Ну и строковые операции тоже нужно исключить, во избежание неожиданных привидений с моторчиком...
И эвал. И рефлексию... и...
 

fixxxer

К.О.
Партнер клуба
Вылысыпыдысты...

На packagist.org по запросам типа math evaluation / math expression стопицот готовых библиотек разной степени паршивости.
 

Sufir

Я не волшебник, я только учусь
Я некоторое время назад парсилку-калькулятор писал, эксперимента ради, на обратной польской кстати: https://github.com/Sufir/php-calc До конца дело так и не довел, сырая, но пользоваться можно.
PHP:
$expr = "round(1/2+(2+3)/(sin(9-2)^2-6/7))*-1";
$parser = new \sufir\Calc\Lexer();
$tokens = $parser->parse($expr);

$converter = new sufir\Calc\Converter;
$tokensPRN = $converter->converToPostfix($tokens);

$calc = new sufir\Calc\Calc;
$calc->registerFunction('sin', function($arg) {
    return sin($arg);
})->registerFunction('round', function($arg) {
    return round($arg, 2);
});

echo $calc->evaluate($tokensPRN);
Только как раз переменные, я по моему и не допилил. В общем можешь взять и доработать или найти что-то аналогичное готовое, наверняка существуют библиотечки.
 

ksnk

прохожий
Вылысыпыдысты...
И тут же следует совет воспользоваться одним из "разной степени паршивости" велосипедов ;)
Разве что Вурдалак советует не велосипед, а симфонический калькулятор :)

Вообще-то, правильный вопрос топикстартеру уже задавался. Кто будет писать формулы и как этот кто-то собирается использовать эти формулы? В зависимости от ответов спектр решений можно ограничить...
 
Сверху