Подтвердить что ты не робот

Когда (если вообще когда-либо) не является злом?

Я слышал много места, что PHP eval функция часто не ответ. В свете PHP 5.3 LSB и закрывает, re из-за причин, зависящих от eval или create_function.

Есть ли какие-либо мыслимые случаи, когда eval является лучшим (только?) ответом в PHP 5.3?

Этот вопрос не о том, является ли eval злом вообще, поскольку, очевидно, это не так.

Сводка ответов:

  • Оценка числовых выражений (или других "безопасных" подмножеств PHP)
  • Тестирование модулей
  • Интерактивная PHP-оболочка
  • Дезабилизация доверенных var_export
  • Некоторые языки шаблонов
  • Создание backdoor для администраторов и/или хакеров
  • Совместимость с < PHP 5.3
  • Проверка синтаксиса (возможно, небезопасная)
4b9b3361

Ответ 1

Эрик Липперт суммирует более трех сообщений в блоге. Это очень интересно читать.

Насколько мне известно, следующие лишь некоторые из причин, по которым используется eval.

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

Ответ 2

Если вы пишете вредоносное ПО, и вы хотите усложнить жизнь системному администратору, который пытается очистить вас. Это, пожалуй, самый распространенный случай использования в моем опыте.

Ответ 3

Основная проблема с eval - это шлюз для вредоносного кода. Таким образом, вы никогда не должны использовать его в контексте, где его можно использовать извне, например. пользователь предоставил вход.

Один действующий UseCase будет в Mocking Frameworks.

Пример из PHPUnit_Framework_TestCase::getMock()

// ... some code before

    $mock = PHPUnit_Framework_MockObject_Generator::generate(
      $originalClassName,
      $methods,
      $mockClassName,
      $callOriginalClone,
      $callAutoload
    );

    if (!class_exists($mock['mockClassName'], FALSE)) {
        eval($mock['code']);
    }

// ... some code after

В методе генерации происходит много всего. В простых условиях: PHPUnit примет аргументы в generate и создаст из него шаблон шаблона. Затем будет eval этот шаблон класса, чтобы сделать его доступным для создания экземпляра. Дело в том, что TestDoubles для издевательства зависимостей в UnitTests конечно.

Ответ 4

Вы можете использовать eval для создания ad-hoc-классов:

function myAutoLoad($sClassName){

   # classic part
   if (file_exists($sClassName.'.php'){

      require $sClassName.'.php';

    } else {

      eval("
            class $sClassName{
                public function __call($sMethod,$aArgs){
                     return 'No such class: ' . $sClassName;
                 }
                }");

    }

} 

Хотя, конечно, использование довольно ограничено (некоторые API или, возможно, DI-контейнеры, платформы тестирования, ORM, которые должны иметь дело с базами данных с динамической структурой, игровыми площадками кодов)

Ответ 5

Если вы пишете сайт, который интерпретирует и выполняет PHP-код, как интерактивная оболочка.

...

Я системный парень, все, что у меня есть.

Ответ 6

eval - это конструкция, которая может использоваться для проверки ошибок синтаксиса.

Скажем, у вас есть эти два скрипта PHP:

script1.php

<?php
// This is a valid syntax
$a = 1;

script2.php

<?php
// This is an invalid syntax
$a = abcdef

Вы можете проверить наличие синтаксических ошибок с помощью eval:

$code1 = 'return true; ?>'.file_get_contents('script1.php');
$code2 = 'return true; ?>'.file_get_contents('script2.php');

echo eval($code1) ? 'script1 has valid syntax' : 'script1 has syntax errors';
echo eval($code2) ? 'script2 has valid syntax' : 'script2 has syntax errors';

В отличие от php_check_syntax (который устарел и удаляется в любом случае), код не будет выполнен.

EDIT:

Другая (предпочтительная) альтернатива - php -l. Вы можете использовать указанное выше решение, если у вас нет доступа к командам системы() или командам оболочки.

Этот метод может вводить классы или функции в ваш код. Обязательно используйте вызов preg_replace или namespace, прежде чем делать это, чтобы предотвратить их выполнение при последующих вызовах.

Что касается темы OP: Когда (если когда-либо) eval NOT evil? eval просто не злой. Программисты злы используют eval без всякой причины. eval может сократить ваш код (оценка математического выражения, например).

Ответ 7

Я обнаружил, что бывают случаи, когда большинство функций языка полезны. В конце концов, даже GOTO имеет своих сторонников. Eval используется в нескольких структурах и хорошо используется. Например, CodeIgniter использует eval для различения иерархии классов PHP 4 и PHP 5. Плагины блога, которые позволяют выполнять PHP-код, определенно нуждаются в нем (и это функция, доступная в Expression Engine, Wordpress и т.д.). Я также использовал его для одного веб-сайта, где серия представлений практически идентична, но для каждого из них необходим индивидуальный код, и создание какого-то безумного механизма правил было намного сложнее и медленнее.

Хотя я знаю, что это не PHP, я обнаружил, что Python eval упрощает реализацию базового калькулятора.

В принципе, здесь вопрос:

  • Помогает ли eval облегчить чтение? Одна из наших главных целей - общаться с другими программистами, что происходит через нашу голову, когда мы написали это. В примере CodeIgniter очень ясно, что они пытались выполнить.
  • Есть ли другой способ? Скорее всего, если вы используете eval (или переменные переменные или любую другую форму синтаксиса строкового поиска или отражения), есть и другой способ сделать это. Вы исчерпали свои другие варианты? У вас есть достаточно ограниченный набор входных данных? Можно ли использовать оператор switch?

Другие соображения:

  • Можно ли сделать это безопасным? Есть ли способ, чтобы блуждающий фрагмент кода мог работать в описании eval?
  • Можно ли это сделать согласованным? Можете ли вы, учитывая ввод, всегда и последовательно производить один и тот же вывод?

Ответ 8

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

Ответ 9

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

Ответ 10

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

Подумайте об этом как о плагине, только о том, что может что-то сделать...

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

Ответ 11

Совместимость. Это довольно часто, чтобы предоставить резервные копии PHP4. Но аналогичным образом это возможное желание эмулировать функциональность PHP5.4 в 5.3, как пример SplString. Хотя просто предоставление двух включенных вариантов (include.php4 vs. include.php5) является частым, иногда более эффективным или читаемым прибегать к eval():

 $IMPL_AA = PHP_VERSION >= 5 ? "implements ArrayAccess" : "";
 eval(<<<END
     class BaseFeature $IMPL_AA {

Где в этом случае код будет работать на PHP4, но выставить более удобный API/синтаксис только на PHP5. Обратите внимание, что этот пример является вымышленным.

Ответ 12

Я использовал eval, когда у меня был бот с php-engined, который общался со мной, и я мог сказать ему делать команды через EVAL: php commands here. Все еще зло, но если ваш код не знает, чего ожидать (на случай, если вы вытащите кусок кода PHP из базы данных), eval - единственное решение.

Ответ 13

Итак, это должно выполняться для всех языков с eval:

В принципе, за небольшим исключением, если вы создаете значение, переданное в eval или получая его из источника, не имеющего права на использование, вы делаете что-то неправильно. То же самое верно, если вы вызываете eval в статической строке.

Помимо проблем с производительностью при инициализации анализатора во время выполнения и проблем безопасности, вы, как правило, входите в систему типов.

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

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

Ответ 14

Непосредственное использование, но модификатор /e для preg_replace использует eval и может быть весьма удобным. См. Пример # 4 на http://php.net/preg_replace.

Является ли это зло/плохой субъективным и полностью зависит от того, что вы считаете "хорошим" в конкретном контексте. При работе с ненадежными входами он обычно считается плохим. Однако в других ситуациях это может быть полезно. Представьте себе однократное преобразование данных script под предельное предельное давление. В этой ситуации, если eval работает и упрощает работу, мне будет сложно называть его злым.

Ответ 15

Это обсуждение eval на самом деле является одним большим недоразумением в контексте php. Люди мыслят о том, что eval является злым, но обычно у них нет проблем с использованием include, хотя включение - это, по сути, одно и то же. Включить foo - это то же самое, что и eval file_get_contents foo, поэтому каждый раз, когда вы включаете то, что вы совершаете, смертный грех eval.