在我用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('#^enum\s*\(\s*\'|\'\s*\)\s*$#', '', $type);
$result = preg_split('#\'\s*,\s*\'#', $type_1);
// possibility two
eval('$result = '.preg_replace('#^enum#','array', $type).';');
Run Code Online (Sandbox Code Playgroud)
Mic*_*cki 129
我会谨慎地调用eval()纯粹的邪恶.动态评估是一种强大的工具,有时可以节省生命.使用eval()可以解决PHP的缺点(见下文).
eval()的主要问题是:
实际使用eval()的主要问题只有一个:
根据经验,我倾向于遵循这个:
Pat*_*sen 40
当只有最轻微的可能性,即在评估的字符串中包含userinput时,eval是邪恶的.如果您在没有来自用户的内容的情况下进行评估,那么您应该是安全的.
尽管如此,在使用eval之前你应该至少考虑两次,它看起来很简单,但是考虑到错误处理(参见VBAssassins注释),可调试性等等,它不再那么简单了.
所以作为一个经验法则:忘了它.当eval是答案时,你可以提出错误的问题!;-)
tho*_*ter 18
eval()在任何时候都同样邪恶.
"什么时候eval()不邪恶?" 在我看来,这是一个错误的问题,因为它似乎暗示使用eval()的缺点在某些情况下神奇地消失了.
使用eval()通常是一个坏主意,因为它会降低代码的可读性,使您能够在运行时预测代码路径(以及可能的安全隐患),从而调试代码.使用eval()还可以防止所评估的代码和从由操作码高速缓存被优化如在Zend Opcache集成到PHP 5.5及以上,或由JIT编译器,如一个在HHVM包围它的代码.
此外,没有必要使用eval()的情况 - PHP是一种没有它的全功能编程语言.
无论你是否真的将这些视为邪恶,或者在某些情况下你可以亲自证明使用eval()取决于你.对某些人来说,邪恶太大了,无法证明这一点,而对于其他人来说,eval()是一个方便的捷径.
但是,如果你看到eval()是邪恶的,它在任何时候都是邪恶的.根据具体情况,它并没有神奇地失去它的邪恶.
Bla*_*ura 14
在这种情况下,eval可能足够安全,只要用户不可能在表中创建任意列.
但它并不是那么优雅.这基本上是一个文本解析问题,滥用PHP的解析器处理似乎有点hacky.如果您想滥用语言功能,为什么不滥用JSON解析器?至少使用JSON解析器,完全没有代码注入的可能性.
$json = str_replace(array(
'enum', '(', ')', "'"), array)
'', '[', ']', "'"), $type);
$result = json_decode($json);
Run Code Online (Sandbox Code Playgroud)
正则表达式可能是最明显的方式.您可以使用单个正则表达式从此字符串中提取所有值:
$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];
Run Code Online (Sandbox Code Playgroud)
Ali*_*xel 11
eval() 很慢,但我不会称之为邪恶.
这是我们对它的不良用处,可能会导致代码注入并且是邪恶的.
一个简单的例子:
$_GET = 'echo 5 + 5 * 2;';
eval($_GET); // 15
Run Code Online (Sandbox Code Playgroud)
一个有害的例子:
$_GET = 'system("reboot");';
eval($_GET); // oops
Run Code Online (Sandbox Code Playgroud)
我建议你不要使用,eval()但如果你这样做,请确保验证/白名单所有输入.
我会公然窃取这里的内容:
Eval本质上总是一个安全问题.
除了安全问题,eval还存在速度极慢的问题.在我对PHP 4.3.10的测试中,它比普通代码慢10倍,在PHP 5.1 beta1上慢28倍.
blog.joshuaeichorn.com:using-eval-in-php
eval()永远是邪恶的。
就个人而言,我认为代码仍然非常邪恶,因为你没有评论它在做什么.它也没有测试其输入的有效性,使其非常脆弱.
我也觉得,由于使用eval的95%(或更多)是积极危险的,因此在其他情况下可能提供的小的潜在时间节省并不值得沉迷于使用它的不良做法.另外,你以后必须向你的小伙子解释为什么你使用eval是好的,而且他们的坏.
当然,你的PHP最终看起来像Perl;)
eval()有两个关键问题,(作为"注入攻击"场景):
1)它可能造成伤害2)它可能只是崩溃
还有一个比社交技术更强的技术:
3)它会引诱人们不恰当地使用它作为其他地方的捷径
在第一种情况下,您将冒险(显然,不是在您评估已知字符串时)执行任意代码.但是,您的输入可能不像您想象的那样已知或固定.
更有可能(在这种情况下)你只会崩溃,你的字符串将以一个无端的模糊错误消息终止.恕我直言,所有代码都应该尽可能整齐地失败,否则它应该抛出一个异常(作为最可处理的错误形式).
我建议,在这个例子中,你是巧合编码而不是编码行为.是的,SQL enum语句(并且你确定该字段的枚举吗? - 你是否调用了正确版本数据库的正确表的正确字段?它实际上是否回答?)恰好看起来像PHP中的数组声明语法,但我建议你真正想做的是找不到从输入到输出的最短路径,而是解决指定的任务:
这大致是您的选项所做的,但为了清晰和安全,我会包装一些if和它的注释(例如,如果第一个匹配不匹配,抛出异常或设置null结果).
转义逗号或引号仍然存在一些可能的问题,您应该解压缩数据然后取消引用它,但它至少将数据视为数据而不是代码.
使用preg_version,最糟糕的结果可能是$ result = null,eval版本最差的是未知的,但至少是崩溃.