Я увлекся и подумал о том, как улучшить его, на самом деле это может быть не ответ на ваш вопрос, а скорее пища для размышлений.Я вижу два решения, и оба типа являются инвазивными.
Конечно, оба решения работают только во всех случаях, если ваша формула использует только «переменные», как в вашем примере с ((WILL*0.8)/2.5)+(LEVEL/4)
.Если у вас есть более сложные формулы, вам придется адаптировать мои решения.
Обтекание eval и не вводить все входные данные в коде eval'd
Предполагая, что формулы находятся под вашим контролеми не предоставленный пользователем, вы могли бы улучшить свой eval, введя не все входные данные в свой eval'd-код, а только формулу.Таким образом, вам не нужно экранировать входные данные, нужно только убедиться, что формула синтаксически верна.
function calculateFormula($_vars, $_values, $_formula) {
// This transforms your formula into PHP code which looks
// like this: (($WILL*0.8)/2.5)+($LEVEL/4)
$_cleanFormula = str_replace(
$_vars,
array_map(function($v) { return '$' . $v; }, $_vars),
$_formula
);
// create the $WILL, $LEVEL, $IQ and $EXP variables in the local scope
extract(array_combine($_vars, $_values));
// execute the PHP-formula
return eval('return ' . $_cleanFormula . ';');
}
// Use it like this, instead of eval
$sucrate = calculateFormula(
array("LEVEL", "EXP", "WILL", "IQ"),
array($player['level'], $player['exp'], $player['will'], $player['IQ']),
$r['crimePERCFORM']);
Это все еще использует eval, так что с точки зрения безопасности это было бы худшим решением.Но это будет ближе всего к тому, что у вас есть сейчас.
Использование языка выражений Symfony
Более безопасный вариант - использовать что-то вроде компонента языка выражений Symfony .Теперь вам не нужна вся платформа Symfony в вашем приложении, компонент языка выражений может использоваться сам по себе.Это может быть большим изменением, это зависит от того, как выглядит ваша существующая кодовая база.Если вы не использовали composer или пространства имен в своем проекте, это изменение может быть слишком большим.
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
$expressionLanguage = new ExpressionLanguage();
$sucrate = $expressionLanguage->evaluate(
$r['crimePERCFORM'],
array(
"LEVEL" => $player['level'],
"EXP" => $player['exp'],
"WILL" => $player['will'],
"IQ" => $player['IQ'],
)
);
Как я уже сказал, это может быть огромное изменение, и вам, возможно, придется познакомиться с composer, если выне знаю уже.