2009-07-26 55 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; 

}