2009-07-26 90 views
13

如果代码是一样的,似乎有之间的差异:PHP:相当于包括使用eval

include 'external.php';

eval('?>' . file_get_contents('external.php') . '<?php');

的区别是什么?有人知道吗?


我知道这两者是不同的,因为include正常工作和eval给出了一个错误。当我最初提出这个问题时,我不确定它是否在所有代码或仅在我的代码上发生了错误(并且因为代码是eval,所以很难找出错误的含义)。但是,在研究了答案之后,事实证明,是否出现错误并不取决于external.php中的代码,而是取决于您的php设置(确切地说short_open_tag)。

+1

感谢您的回答。它帮助了这个:https://github.com/tedivm/Stash/pull/135 – CMCDragonkai 2014-03-15 17:52:25

回答

13

经过一番更多的研究后,我发现自己出了什么问题。问题在于<?php是一个“短开标签”,因此只有在short_open_tag设置为1(在php.ini中或类似效果)时才有效。正确的完整标记是<?php,在第二个p之后有一个空格。

作为的包括诸如适当的等价物是:

eval('?>' . file_get_contents('external.php') . '<?php '); 

或者,你可以离开了开放标签的所有在一起(如在下面的评论中所指出):

eval('?>' . file_get_contents('external.php')); 

我原来的解决方案是添加一个分号,这也适用,但如果你问我看起来不那么干净:

eval('?>' . file_get_contents('external.php') . '<?php;'); 
6

AFAIK如果您使用eval(),则无法利用php加速器。

+3

AFAIK你必须在文件系统上有一个真实的文件。 – niteria 2009-07-26 21:36:46

+0

......除非你有性能问题,否则你不应该担心它。 – niteria 2009-07-26 21:43:14

+0

我的意思是AFAIK php加速器只能用于文件系统上的真实文件。构建PHP加速器很可能会使代码复杂化(您必须检查文件是否可写)等等,并且可能不会有任何明显的改进。如果他们只是模板文件,我的猜测是它不会改变任何东西。 – niteria 2009-07-26 22:14:26

5

如果您使用的是已安装操作码缓存的网络服务器,如APC,eval将不会是“最佳解决方案”:如果我没有记错,评估代码未存储在操作码缓存中(和另一个答案说同样的事情,顺便说一句)

可以使用,至少如果代码是不经常改变的解决方案,为获得存储在数据库中的代码结构和包含的代码:

  • 必要时,取从数据库的代码,并存储它在磁盘上的文件
  • 包括文件
  • 因为现在该代码在一个文件,在磁盘上,操作码缓存将能够缓存它 - 这是演出
  • 更好,你将不再需要每次必须执行代码时向DB提出请求。

我与使用该解决方案(在磁盘上的文件是不超过存储在数据库的代码缓存更多)软件的工作,我的工作不是太糟糕了 - 更好的方式,这样做的负载每一页,反正DB请求......

一些不那么好的东西,作为一个后果:

  • 你必须获取从数据库的代码把它在文件中“必要时”
    • 这可能意味着重新基因每小时评估临时文件一次,还是在修改数据库中的条目时将其删除?你有办法确定这种情况何时发生?
  • 你也必须改变你的代码,使用临时文件,或在必要时重新生成它
    • ,如果你有几个地方modifiy,这可能意味着一些工作

顺便说一句:我敢说“eval是邪恶的”吗?

0

这可以让你有一个文件假设文件封装器是包含在PHP:

function stringToTempFileName($str) 
{ 
    if (version_compare(PHP_VERSION, '5.1.0', '>=') && strlen($str < (1024 * 512))) { 
     $file = 'data://text/plain;base64,' . base64_encode($str); 
    } else { 
     $file = Utils::tempFileName(); 
     file_put_contents($file, $str); 
    } 
    return $file; 
} 

...然后,包括“文件”。是的,这也会禁用操作码缓存,但它使得这个'eval'与行为相同。

1

只有eval('?>' . file_get_contents('external.php'));变体是正确的替代包括。

见测试:

<?php 
$includes = array(
    'some text', 
    '<?php print "some text"; ?>', 
    '<?php print "some text";', 
    'some text<?php', 
    'some text<?php ', 
    'some text<?php;', 
    'some text<?php ?>', 
    '<?php ?>some text', 
); 

$tempFile = tempnam('/tmp', 'test_'); 

print "\r\n" . "Include:" . "\r\n"; 
foreach ($includes as $include) 
{ 
    file_put_contents($tempFile, $include); 
    var_dump(include $tempFile); 
} 

unlink($tempFile); 

print "\r\n" . "Eval 1:" . "\r\n"; 
foreach ($includes as $include) 
    var_dump(eval('?>' . $include . '<?php ')); 

print "\r\n" . "Eval 2:" . "\r\n"; 
foreach ($includes as $include) 
    var_dump(eval('?>' . $include)); 

print "\r\n" . "Eval 3:" . "\r\n"; 
foreach ($includes as $include) 
    var_dump(eval('?>' . $include . '<?php;')); 

输出:

Include: 
some textint(1) 
some textint(1) 
some textint(1) 
some text<?phpint(1) 
some textint(1) 
some text<?php;int(1) 
some textint(1) 
some textint(1) 

Eval 1: 
some textNULL 
some textNULL 
bool(false) 
some text<?phpNULL 
bool(false) 
some text<?php;NULL 
some textNULL 
some textNULL 

Eval 2: 
some textNULL 
some textNULL 
some textNULL 
some text<?phpNULL 
some textNULL 
some text<?php;NULL 
some textNULL 
some textNULL 

Eval 3: 
some text<?php;NULL 
some text<?php;NULL 
bool(false) 
some text<?php<?php;NULL 
bool(false) 
some text<?php;<?php;NULL 
some text<?php;NULL 
some text<?php;NULL 
2

正如this answer to my question注意到@bwoebi,所述eval取代不尊重所包含的文件的文件路径上下文。作为一个测试案例:

Baz.php

<?php return __FILE__; 

Foo.php

<?php 
echo eval('?>' . file_get_contents('Baz.php', FILE_USE_INCLUDE_PATH)) . "\n"; 
echo (include 'Baz.php') . "\n"; 

执行php Foo.php的结果:

$ php Foo.php 
/path/to/file/Foo.php(2) : eval()'d code 
/path/to/file/Baz.php 

我不知道任何方式改变__FILE__常量和朋友在运行时,s o我认为根据eval来定义include没有任何通用的方法。

0

这里是我的做法。

它创建临时php文件并包含它。

,但如果你想在这个函数运行的代码有错误程序退出时删除临时文件

这样过,所以我使功能的自动清洗程序。这种方式可以在每次运行函数时通过超时清理旧的临时文件。你可以设置超时或从功能启动选项禁用它

我还添加了忽略错误选项来解决未删除的临时文件。如果错误被忽略,程序将继续并删除临时文件。

也有些项目必须禁用autoclean,因为它每次运行时都会扫描整个目录。它可能会损害磁盘性能。

function eval2($c) { 
    $auto_clean_old_temporary_files=false; //checks old temporary eval2 files for this spesific temporary file names generated by settings below 
    $ignore_all_errors=true; //if you ignore errors you can remove temporary files even there is an error 

    $tempfiledirectory=''; //temporary file directory 
    $tempfileheader='eval2_'; // temporary file header 
    $tempfiletimeseperator='__'; // temporary file seperator for time 
    $tempfileremovetimeout=200; // temp file cleaning time in seconds 

    if ($auto_clean_old_temporary_files===true) { 

     $sd=scandir('.'); //scaning for old temporary files 
     foreach ($sd as $sf) { 
      if (strlen($sf)>(32+strlen($tempfileheader)+strlen($tempfiletimeseperator)+3)) { // if filename long enough 
       $t1=substr($sf,(32+strlen($tempfileheader)),strlen($tempfiletimeseperator)); //searching time seperator 
       $t2=substr($sf,0,strlen($tempfileheader)); //searching file header 

       if ($t1==$tempfiletimeseperator && $t2==$tempfileheader) { //checking for timeseperator and file name header 
        $ef=explode('.',$sf); 
        unset($ef[count($ef)]);//removing file extension 
        $nsf=implode('.',$ef);//joining file name without extension 

        $ef=explode($tempfiletimeseperator,$nsf); 
        $tm=(int)end($ef); //getting time from filename 

        $tmf=time()-$tm; 
        if ($tmf>$tempfileremovetimeout && $tmf<123456 && $tmf>0) { // if time passed more then timeout and difference with real time is logical 
         unlink($sf); // finally removing temporary file 
        } 
       } 
      } 
     } 
    } 

    $n=$tempfiledirectory.$tempfileheader . md5(microtime().rand(0,5000)). $tempfiletimeseperator . time() .'.php'; //creating spesific temporary file name 
    $c='<?php' . PHP_EOL . $c . PHP_EOL; //generating php content 
    file_put_contents($n,$c); //creating temporary file 

    if ($ignore_all_errors===true) { // including temporary file by your choise 
     [email protected]($n); 
    }else{ 
     $s=include($n); 
    } 

    return $s; 

}