Когда eval зло в php?


за все годы, что я разрабатывал php, я всегда слышал, что с помощью eval() это зло.

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

// $type is the result of an SQL statement
// e.g. SHOW COLUMNS FROM a_table LIKE 'a_column';
// hence you can be pretty sure about the consistency
// of your string
$type = "enum('a','b','c')";

// possibility one
$type_1 = preg_replace('#^enums*(s*'|'s*)s*$#', '', $type);
$result = preg_split('#'s*,s*'#', $type_1);

// possibility two
eval('$result = '.preg_replace('#^enum#','array', $type).';');
18 77

18 ответов:

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

основные проблемы с eval () являются:

  • потенциально небезопасных ввода. передача ненадежного параметра-это способ сбоя. Это часто нетривиальная задача, чтобы убедиться, что параметр (или его часть) полностью доверившийся.
  • загвоздка. использование eval () делает код умным, поэтому его сложнее отслеживать. Цитируя Брайана Кернигана"отладка в два раза сложнее, чем написание кода в первую очередь. Поэтому, если вы пишете код как можно умнее, вы, по определению, недостаточно умны, чтобы отлаживать его"

основная проблема с фактическим использованием eval () только одна:

  • неопытные разработчики, которые используют его без хватит размышлять.

Как правило, я стараюсь следовать этому:

  1. иногда eval () является единственным/правильным решением.
  2. в большинстве случаев следует попробовать что-то другое.
  3. если не уверен, Гото 2.
  4. еще, будьте очень, очень осторожны.

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

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

Итак, как правило,: Забыть об этом. Когда eval-это ответ вы, вероятно, задаете неправильный вопрос! ; -)

eval () одинаково зол во все времена.

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

использование eval (), как правило, плохая идея, потому что это уменьшает читаемость кода, возможность для вас предсказать путь кода (и возможные последствия для безопасности этого) перед выполнением, и, следовательно, возможность отладки кода. Использование eval () также может предотвратить оптимизацию вычисляемого кода и окружающего его кода с помощью кэша кодов операций, такого как Zend Opcache, интегрированного в PHP 5.5 и выше, или с помощью JIT-компилятора, такого как HHVM.

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

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

однако, если вы видите eval () как зло, это зло во все времена. Она не теряет своей злобы магическим образом в зависимости от контекста.

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

это на самом деле не более элегантно, хотя. Это в основном проблема разбора текста, и злоупотребление синтаксическим анализатором PHP для обработки кажется немного хаки. Если вы хотите злоупотреблять языковыми функциями, почему бы не злоупотреблять синтаксическим анализатором JSON? По крайней мере, с помощью парсера JSON нет никакой возможности для инъекции кода.

$json = str_replace(array(
    'enum', '(', ')', "'"), array)
    '',     '[', ']', "'"), $type);
$result = json_decode($json);

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

$extract_regex = '/
    (?<=,|enum\()   # Match strings that follow either a comma, or the string "enum("...
    \'      # ...then the opening quote mark...
    (.*?)       # ...and capture anything...
    \'      # ...up to the closing quote mark...
    /x';
preg_match_all($extract_regex, $type, $matches);
$result = $matches[1];

когда вы используете внешние данные (например, пользовательский ввод) внутри eval.

в вашем примере выше, это не проблема.

eval() медленно, но я бы не назвал это злом.

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

простой пример:

$_GET = 'echo 5 + 5 * 2;';
eval($_GET); // 15

вредный пример:

$_GET = 'system("reboot");';
eval($_GET); // oops

Я бы посоветовал вам не использовать eval() но если вы это сделаете, убедитесь, что вы проверяете / белый список всех входных данных.

Я нагло украду контент здесь:

  1. Eval по своей природе всегда будет проблемой безопасности.

  2. помимо проблем безопасности eval также имеет проблему быть невероятно медленным. В моем тестировании на PHP 4.3.10 его 10 раз медленнее, чем обычный код и 28 раз медленнее на PHP 5.1 beta1.

blog.joshuaeichorn.com: using-eval-in-php

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

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

и, конечно же, ваш PHP выглядит как Perl ;)

есть две ключевые проблемы с eval (), (как сценарий" инъекционной атаки"):

1) это может причинить вред 2) он может просто разбиться

и тот, который больше-социальный, чем технический:

3) это будет соблазнять людей использовать его неуместно в качестве ярлыка в другом месте

в первом случае вы рискуете (очевидно, не тогда, когда вы оцениваете известную строку) произвольно выполнение кода. Однако ваши входные данные могут быть не такими известными или фиксированными, как вы думаете.

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

Я бы предположил, что в этом примере вы кодируете по совпадению, а не кодируете поведение. Да, Оператор enum SQL (и вы уверены, что это поле перечисление? - вы назвали правильное поле правильной таблицы правильной версии базы данных? Он действительно ответил?) бывает похоже на синтаксис объявления массива в PHP, но я бы предложил, что вы действительно хотите сделать, это не найти кратчайший путь от входа до выхода, а скорее решить указанную задачу:

  • определите, что у вас есть перечисление
  • извлечь внутренний список
  • распаковать список значения

Это примерно то, что делает ваш вариант, но я бы обернул некоторые if и комментарии вокруг него для ясности и безопасности (например, если первое совпадение не совпадает, бросьте исключение или установите нулевой результат).

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

с preg_version ваш худший результат, вероятно, будет be $result=null, с версией eval худшее неизвестно, но по крайней мере сбой.

Я бы также уделил некоторое внимание людям, поддерживающим ваш код.

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

eval оценивает строку как код, проблема с этим заключается в том, что если строка каким-либо образом "испорчена", она может подвергать огромные угрозы безопасности. Обычно проблема заключается в том, что пользовательский ввод оценивается в строке во многих случаях пользователь может ввести код (например, php или ssi), который затем запускается в eval, он будет работать с теми же разрешениями, что и ваш PHP-скрипт, и может использоваться для получения информации/доступа к вашему серверу. Это может быть довольно сложно, чтобы убедиться, что пользовательский ввод правильно вычистил перед тем, как передать его эвалу. Есть и другие проблемы... некоторые из которых являются спорными

PHP советует вам написать свой код таким образом, чтобы он мог выполняться через call_user_func вместо выполнения явных оценок.

eval() и всегда зло.

  • по соображениям безопасности
  • для повышения производительности
  • по причинам читаемости / многократного использования
  • по причинам IDE / tool
  • для отладки причинам
  • всегда есть лучший способ

другая причина eval это зло, что он не может кэшироваться PHP байт-код кэшей, таких как eAccelertor или ACP.

это плохое программирование, которое делает eval () злым, а не функцию. Я использую его иногда, так как не могу обойти его в динамическом программировании на нескольких сайтах. Я не могу иметь PHP разбирается на одном сайте, так как я не буду получать то, что я хочу. Я бы просто получил результат! Я счастлив, что функция eval () существует, так как это делает мою жизнь намного проще. Пользовательский ввод? Только плохие программисты подключаются к хакерам. Меня это не волнует.

это плохое программирование, которое делает eval () злым, а не функцию. Я использую его иногда, так как не могу обойти его в динамическом программировании на нескольких сайтах. Я не могу иметь PHP разбирается на одном сайте, так как я не буду получать то, что я хочу. Я бы просто получил результат! Я счастлив, что функция eval () существует, так как это делает мою жизнь намного проще. Пользовательский ввод? Только плохие программисты подключаются к хакерам. Меня это не волнует.

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

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

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

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

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

чтобы выполнить статический вызов, создайте свой обратный вызов в виде массива ('class_name', 'method_name') или даже в виде простой строки, такой как 'class_name::method_name'. Для выполнения динамического вызова используется обратный вызов в стиле array($object, 'method').

только разумное использование для eval () заключается в написании пользовательского компилятора. Я сделал один, но eval все еще злой, потому что это так чертовски трудно отладить. Хуже всего то, что фатальная ошибка в evaled-коде приводит к сбою кода, который его вызвал. Я использовал расширение Parsekit PECL, чтобы проверить синтаксис по крайней мере, но все равно не радость - попробуйте сослаться на неизвестный класс и все сбои приложения.

кроме проблем безопасности, eval () не может быть скомпилирован, оптимизирован или кэширован опкодом, поэтому он всегда будет медленнее -- путь медленнее -- чем обычный php код. Таким образом, нецелесообразно использовать eval, хотя это не делает его злым. (goto зло eval это только плохая практика / вонючий код / уродливый)

вот решение для запуска PHP-кода, извлеченного из базы данных без использования eval. Позволяет для всех в области функций и исключений:

$rowId=1;  //database row id
$code="echo 'hello'; echo '\nThis is a test\n'; echo date(\"Y-m-d\");"; //php code pulled from database

$func="func{$rowId}";

file_put_contents('/tmp/tempFunction.php',"<?php\nfunction $func() {\n global $rowId;\n$code\n}\n".chr(63).">");

include '/tmp/tempFunction.php';
call_user_func($func);
unlink ('/tmp/tempFunction.php');

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