create_function в PHP устарела

<?php

function compute($input){

        $compute = create_function('', 'return '.$input.';');
        return 0 + $compute();
    
}

$test = array(
    '5 + 5',
    '3 +( 2 * 3)',
    '(3 + 2) * 3',
    '3 + 2 * 3',
    '(3-2-1)*3'
    
);

foreach( $test AS $string){
    echo compute( $string);
    echo "<br />";
}

http://sandbox.onlinephpfunctions.com/code/61ee53b5477d7450ff89b15e4f08

Приведенный выше код устарел в PHP 7.2. Большинству других людей, у которых была эта проблема, было сказано использовать анонимную функцию. Но в данном случае я не знаю, как им пользоваться.


person Alexander Weixelbaumer    schedule 18.07.2018    source источник
comment
Я никогда не знал об этой функции (это действительно страшно), но страница документа предупреждает, что она использует eval. По совпадению (или нет) это функция, которую вы можете использовать для синтаксического анализа вашего массива в исполняемый код (что вы и делаете: у вас есть строка, которую вы хотите запустить). Предупреждение: eval - это не то, что вы хотите делать легкомысленно, но, поскольку вы уже делаете это в основном, вы можете продолжать использовать его, я думаю :)   -  person Nanne    schedule 18.07.2018
comment
Нет ничего постыдного в использовании функций, которые отличают динамические языки от компилируемых языков. eval() - это то, что вы должны здесь использовать, учитывая, что он не содержит пользовательского ввода. В противном случае можно было бы использовать слегка сложное утверждение регулярного выражения.   -  person mario    schedule 18.07.2018
comment
Марио хорошо замечает, что eval без ввода данных пользователем в целом более безопасен. Вы можете пойти еще дальше и сказать, что тщательно проверенный код, вводимый пользователем, тоже подойдет, например формулы, которые прошли тщательную проверку администратором перед тем, как быть допущены в систему.   -  person braindigitalis    schedule 18.07.2018
comment
stackoverflow.com/q/5057320/2943403   -  person mickmackusa    schedule 18.07.2018
comment
stackoverflow.com/q/1804249/2943403   -  person mickmackusa    schedule 18.07.2018
comment
18880772 использует именно мою функцию - потому что это то, откуда она взялась ..   -  person Alexander Weixelbaumer    schedule 18.07.2018


Ответы (2)


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

Если проблема, которую вы пытаетесь решить, является вашим тестовым примером, то либо используйте eval (с проверенными входными данными - /^[^0-9 +-*\/\(\)]$/), либо используйте lib, специально разработанная для разрешения таких выражений.

Если вы не пытаетесь реализовать полиморфный код, тогда анонимные функции просты (которые по совпадению реализуют полиморфный код!):

$compute = function () use ($arg) {
      if (preg_match('/^[^0-9 +-*\/\(\)]$/', $arg)) {
           return eval('return '.$arg . ';');
      }
      return false;
  };
person symcbean    schedule 18.07.2018
comment
Код, который вы написали выше, IS EVAL, и вы не поняли, почему вам было сказано не использовать eval () - person symcbean; 18.07.2018
comment
... и вы также никогда не упоминали об ограничении в своем вопросе - хотя ваш код эффективно демонстрирует, почему он глуп. - person symcbean; 18.07.2018
comment
Пожалуйста, объясните посимвольно, что, по вашему мнению, делает ваш шаблон регулярного выражения, и почему вы решили написать его именно так. - person mickmackusa; 18.07.2018
comment
@mickmackuse: Нет. Если вы считаете, что мой код можно использовать для взлома, предоставьте доказательства. - person symcbean; 19.07.2018

Подойдет простой парсер, возможно, рекурсивный спуск, или вроде этот хорошо, если вы ДЕЙСТВИТЕЛЬНО хотите продолжать использовать PHP для всего решения. Вы можете довольно легко использовать такую ​​систему для оценки пользовательских формул, не прибегая к eval.

Лично мне нужно что-то, что могло бы безопасно оценивать всю функцию в php (с циклами, условными операторами и т. Д.), Поэтому я использовал очень легкий интерпретатор javascript под названием duktape, который может быть скомпилирован в php 7 как модуль. Затем вы можете вызвать его для оценки функций javascript, которые являются упрощенными по своей природе и не имеют возможностей ввода / вывода, за исключением возможности возвращать значение и принимать входные данные из исходного сценария.

Вот как я это сделал:

    /* Execute a javascript function. Requires the duktape extension to be included in PHP.
     * Accepts an array of variables by name to include as parameters to the called code.
     * The code is expected to return a value, which should be scalar (numeric, string or null).
     */
    function jsfunction($inputs, $code)
    {
            $duktape = new Duktape();

            $javascript = "function e() {";
            foreach ($inputs as $name=>$value) {
                    $javascript .= "var " . $name . ' = ' . json_encode((object)$value) . ";\n";
            }
            $javascript .= $code . "}\ne();";

            try {
                    $result = $duktape->eval($javascript);
            }
            catch (Exception $e) {
                    return null;
            }
            return $result;
    }

Параметры должны передаваться в виде массива пар имя / значение, например передача ['a' => 42] делает переменную с именем 'a' видимой для javascript со значением 42. $ code содержит тело функции javascript без фигурных скобок, которое должно заканчиваться оператором return.

Надеюсь это поможет!

person braindigitalis    schedule 18.07.2018
comment
Также важно отметить, что duktape - действительно хорошая библиотека, однако она довольно проста и примитивна по дизайну. Это делает его идеальным для этого решения, поскольку вы знаете, что не существует простого способа, например, использовать вызов файловой системы или получить веб-страницу. Однако, когда он выдает ошибку, он выдает только общий объект Exception, на самом деле нет никаких деталей, поэтому вам, вероятно, следует внимательно проверить свои формулы перед их использованием, просто чтобы избежать ненужной путаницы. - person braindigitalis; 18.07.2018