Nickolay.info. PHP. Статьи. Простейший калькулятор на функции PHP eval() |
Этот небольшой калькулятор написан в учебных целях примерно за полчаса, цель - показать использование регулярных выражений на практике. Не следует забывать, что применение eval к любым пользовательским данным опасно и лишь тщательная "фильтрация" любых полученных от пользователя данных может эту опасность снизить.
Что умеет и чего не умеет калькулятор: знает арифметические операции + / * - % (остаток от деления) ^ (степень),
функции sin, sinh, cos, cosh, tan, tanh, abs, acos, acosh, asin, asinh, atan, atanh, exp, log, log10, deg2rad, rad2deg,
sqrt, ceil, floor, round, число pi, скобки. Не знает: вычислений по цепочке, то есть, (1+rad2deg(sin(pi/2)))/2
наш калькулятор вычислит, (1+2)+3
- тоже, а вот 1+2+3
- уже нет.
Чтобы научить его это делать, поправьте шаблоны в исходнике.
Вся реализация, собственно, вот:
//Строка ввода в переменной $text $number = '(?:\d+(?:[,.]\d+)?|pi)'; //Шаблон для числа $functions = '(?:sinh?|cosh?|tanh?|abs|acosh?|asinh?|atanh?|exp|log10|log|deg2rad|rad2deg|sqrt|ceil|floor|round)'; //Разрешенные функции PHP $operators = '[+\/*\^%-]'; //Разрешенные математические действия $regexp = '/^(('.$number.'|'.$functions.'\s*\((?1)+\)|\((?1)+\))(?:'.$operators.'(?2))?)+$/'; //Окончательная оценка if (preg_match($regexp, $text)) { $text = preg_replace('!pi!', 'pi()', $text); //pi придётся записать функцией $text = preg_replace('~([0-9]+)\^([0-9]+)~e', 'pow("\\1", "\\2")', $text); //и учесть степень eval('$result = '.$text.';'); //Сам калькулятор :) } else { $result = 'Error!'; } echo '<p align="center"><b>Result=</b>'.$result.'</p>';
Конечно, этот код очень примитивен, служит только для примера и может улучшаться. Так, приведённый фрагмент "понимает" возведение только целого числа в целую в степень, знак "-" перед числом не входит в шаблон, следовательно, не может быть отличён скриптом от операции вычитания и т.д.
Калькулятор PHP на функции eval() в работе
Исходник калькулятора (2 Кб)
P.S. В обсуждении этого подхода один из слушателей сразу же высказал мнение, что
нужно исходить из того, что без пробелов в коде и с 50-ю символами ввода
(строка $text
у нас на всякий случай обрезается на стороне сервера)
злой хакер едва-ли сумеет что-нибудь сделать, так что процитированную выше часть скрипта
вполне можно сделать и такой:
//Строка ввода в переменной $text $result=''; @eval('$result = '.$text.';'); //Сам калькулятор :) if (!is_numeric($result)) $result = 'Error!'; echo '<p align="center"><b>Result=</b>'.$result.'</p>';
- то есть, просто не выводить результат, если он не числовой, а выполнять всё подряд... увы, простейшее
unlink('calc.php');
в поле ввода данную идею начисто опровергло :)
гостевая; E-mail |