PHP:相当于包括使用eval
如果代码是一样的,似乎有之间的差异:PHP:相当于包括使用eval
include 'external.php';
和
eval('?>' . file_get_contents('external.php') . '<?php');
的区别是什么?有人知道吗?
我知道这两者是不同的,因为include
正常工作和eval
给出了一个错误。当我最初提出这个问题时,我不确定它是否在所有代码或仅在我的代码上发生了错误(并且因为代码是eval
,所以很难找出错误的含义)。但是,在研究了答案之后,事实证明,是否出现错误并不取决于external.php
中的代码,而是取决于您的php设置(确切地说short_open_tag
)。
经过一番更多的研究后,我发现自己出了什么问题。问题在于<?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;');
如果您使用的是已安装操作码缓存的网络服务器,如APC,eval
将不会是“最佳解决方案”:如果我没有记错,评估代码未存储在操作码缓存中(和另一个答案说同样的事情,顺便说一句)。
可以使用,至少如果代码是不经常改变的解决方案,为获得存储在数据库中的代码结构和包含的代码:
- 必要时,取从数据库的代码,并存储它在磁盘上的文件
- 包括文件
- 因为现在该代码在一个文件,在磁盘上,操作码缓存将能够缓存它 - 这是演出
- 更好,你将不再需要每次必须执行代码时向DB提出请求。
我与使用该解决方案(在磁盘上的文件是不超过存储在数据库的代码缓存更多)软件的工作,我的工作不是太糟糕了 - 更好的方式,这样做的负载每一页,反正DB请求......
一些不那么好的东西,作为一个后果:
- 你必须获取从数据库的代码把它在文件中“必要时”
- 这可能意味着重新基因每小时评估临时文件一次,还是在修改数据库中的条目时将其删除?你有办法确定这种情况何时发生?
- 你也必须改变你的代码,使用临时文件,或在必要时重新生成它
- ,如果你有几个地方modifiy,这可能意味着一些工作
顺便说一句:我敢说“eval是邪恶的”吗?
这可以让你有一个文件假设文件封装器是包含在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'与行为相同。
只有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
正如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
没有任何通用的方法。
这里是我的做法。
它创建临时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;
}
感谢您的回答。它帮助了这个:https://github.com/tedivm/Stash/pull/135 – CMCDragonkai 2014-03-15 17:52:25