14

如果代码相同,则似乎存在以下差异:

include 'external.php';

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

有什么不同?有人知道吗?


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

4

8 回答 8

14

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

因此,包含的适当等价物是:

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

或者,您可以将开始标签放在一起(如下面的评论中所述):

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

我最初的解决方案是添加一个分号,这也可以,但如果你问我,它看起来不太干净:

eval('?>' . file_get_contents('external.php') . '<?php;');
于 2009-07-26T14:06:51.373 回答
6

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

于 2009-07-26T13:54:08.423 回答
6

如果您使用的是安装了操作码缓存的网络服务器,例如APCeval则不会是“最佳解决方案”:如果我没记错的话,eval'd 代码不会存储在操作码缓存中(另一个答案也一样事情,顺便说一句)

至少在代码不经常更改的情况下,您可以使用的解决方案是混合存储在数据库中的代码和包含的代码:

  • 必要时,从数据库中获取代码,并将其存储在磁盘上的文件中
  • 包括那个文件
  • 由于代码现在在文件中,在磁盘上,操作码缓存将能够缓存它——这对性能更好
  • 并且每次必须执行代码时都不需要向数据库发出请求。

我使用过使用此解决方案的软件(磁盘上的文件只不过是存储在 DB 中的代码的缓存),而且我的工作还不错——比对每个页面执行大量 DB 请求要好得多,反正...

结果是一些不太好的事情:

  • 您必须从数据库中获取代码以“在必要时”将其放入文件中
    • 这可能意味着每小时重新生成一次临时文件,或者在数据库中的条目被修改时将其删除?您有办法确定何时发生这种情况吗?
  • 您还必须更改代码、使用临时文件或在必要时重新生成它
    • 如果你有几个地方要修改,这可能意味着一些工作

顺便说一句:我敢说“eval is evil”之类的话吗?

于 2009-07-26T14:24:44.700 回答
2

正如@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__在运行时更改常量和朋友,所以我认为没有任何通用的方法来include定义eval.

于 2014-05-15T15:11:56.263 回答
1

这允许您包含一个文件,假设包含的文件包装器在 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;
}

...然后包括那个“文件”。是的,这也将禁用操作码缓存,但它使这个“评估”与行为方面的包含相同。

于 2010-04-13T20:59:21.807 回答
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
于 2013-10-07T17:14:34.830 回答
1

关于上述解决方案的一些想法:

临时文件

不。这对性能非常不利,请不要这样做。它不仅使您的操作码缓存完全疯狂(缓存命中永远不会发生+它每次都会尝试再次缓存它)而且还会让您在高(甚至中等)负载下文件系统锁定令人头疼,因为您必须编写文件和Apache/PHP 必须阅读它。

简单的 eval()

在极少数情况下可以接受;不要经常这样做。实际上它没有被缓存(糟糕的操作码缓存只是不知道它是和以前一样的字符串);同时,如果您的代码每次都在更改,那么 eval 比 include() 好很多,主要是因为 include() 在每次调用时都会填满操作码缓存。就像 tempfile 的情况一样。这太可怕了(慢了约 4 倍)。

内存中的 eval()

实际上,当您的脚本已经在字符串中时, eval非常快;大多数时候是磁盘操作将其拉回,现在这当然取决于您在脚本中执行的操作,但在我的非常小的脚本情况下,它快了约 400 倍。(你有 memcached 吗?只是想大声)所以 include() 不能做的是在没有文件操作的情况下对同一件事进行两次评估,这非常重要。如果你将它用于不断变化的、小的、内存生成的字符串,显然它是 eval 的选择 - 一次又一次地加载一次 + eval 比迭代的 include() 快很多倍。

TL;博士

  • 相同的代码,每个请求一次:包括
  • 相同的代码,每个请求多次调用:eval
  • 不同的代码:eval
于 2018-09-21T13:45:45.267 回答
0

这是我的方法。

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

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

所以我在功能上做了一个自动清洁程序。这样,每次函数运行时,它都会通过超时清除旧的临时文件。您可以在功能开始时从选项中设置超时或禁用它

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

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

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 
        $s=@include($n);
    }else{
        $s=include($n);
    }

    return $s;  

}
于 2017-11-02T00:10:38.250 回答