2009-07-26 30 views
13

Nếu mã là như nhau, dường như có một sự khác biệt giữa:PHP: Tương đương của bao gồm sử dụng eval

include 'external.php';

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

sự khác biệt là gì? Có ai biết không?


Tôi biết hai là khác nhau vì include hoạt động tốt và eval đưa ra một lỗi. Khi tôi hỏi câu hỏi ban đầu, tôi không chắc liệu nó có đưa ra lỗi trên tất cả mã hay chỉ trên tôi (và vì mã là eval ed, rất khó để tìm ra lỗi có ý nghĩa gì). Tuy nhiên, sau khi nghiên cứu câu trả lời, nó chỉ ra rằng có hay không bạn nhận được lỗi không phụ thuộc vào mã trong external.php, nhưng không phụ thuộc vào các thiết lập php của bạn (short_open_tag để được chính xác).

+1

Cảm ơn câu hỏi này. Nó đã giúp với điều này: https://github.com/tedivm/Stash/pull/135 – CMCDragonkai

Trả lời

13

Sau một số nghiên cứu khác, tôi đã phát hiện ra chính mình đã làm gì sai. Vấn đề là trong thực tế là <?php là một "thẻ mở ngắn" và do đó sẽ chỉ hoạt động nếu short_open_tag được đặt thành 1 (trong php.ini hoặc một cái gì đó để cùng một hiệu ứng). Thẻ đầy đủ chính xác là <?php, có khoảng trắng sau p thứ hai.

Như vậy tương đương thích hợp bao gồm là:

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

Ngoài ra, bạn có thể để lại thẻ mở ra tất cả với nhau (như đã nêu trong các ý kiến ​​dưới đây):

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

ban đầu của tôi giải pháp là thêm dấu chấm phẩy, cũng hoạt động, nhưng trông kém sạch sẽ hơn nhiều nếu bạn hỏi tôi:

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

cảm ơn vì lừa dấu chấm phẩy, nó đã khiến tôi phát điên! – amrtn

+1

không phải là eval ("?>". File_get_contents ('external.php')); giống như bao gồm 'external.php'; ?? –

+0

YuriKolovsky, bạn có quyền bỏ qua các thẻ mở php là một thay thế để theo dõi nó với một dấu chấm phẩy. – Jasper

6

AFAIK bạn không thể tận dụng lợi thế của bộ tăng tốc php nếu bạn sử dụng eval().

+3

AFAIK bạn phải có một tập tin thực sự trên hệ thống tập tin. – niteria

+0

... và bạn không nên lo lắng về điều đó trừ khi bạn gặp vấn đề về hiệu suất. – niteria

+0

Tôi có nghĩa là AFAIK php accelerators chỉ làm việc với các tập tin thực sự trên hệ thống tập tin. Xây dựng cho các máy gia tốc php sẽ rất có thể làm phức tạp mã của bạn (bạn phải kiểm tra xem các tệp có ghi được hay không) và có thể nó sẽ không thực hiện bất kỳ cải tiến rõ ràng nào. Nếu chúng chỉ là các tệp mẫu, tôi đoán là nó sẽ không thay đổi gì cả. – niteria

5

Nếu bạn đang sử dụng máy chủ web mà bạn đã cài đặt bộ nhớ cache opcode, như APC, eval sẽ không là "giải pháp tốt nhất": mã được đánh giá không lưu trữ trong bộ nhớ cache opcode, nếu tôi nhớ chính xác (và một câu trả lời khác cũng nói như vậy, btw).

Một giải pháp bạn có thể sử dụng, ít nhất là nếu mã không thường xuyên thay đổi, là có được một hỗn hợp của mã được lưu trữ trong cơ sở dữ liệu và bao gồm mã:

  • khi cần thiết, lấy mã từ DB, và lưu trữ nó trong một tập tin trên đĩa
  • bao gồm tập tin đó
  • như mã hiện đang trong một tập tin, trên đĩa, bộ nhớ cache opcode sẽ có thể cache nó - đó là tốt hơn cho màn trình diễn
  • và bạn sẽ không cần để thực hiện yêu cầu tới DB mỗi lần bạn phải thực thi mã.

Tôi đã làm việc với phần mềm sử dụng giải pháp này (tệp trên đĩa không nhiều hơn bộ nhớ cache của mã được lưu trữ trong DB) và tôi đã làm việc không tốt DB yêu cầu của mỗi trang, dù sao ...

một số điều không tốt như vậy, như một hệ quả:

  • bạn phải lấy mã từ DB để đặt nó trong tập tin "khi cần thiết"
    • điều này có thể có nghĩa là tái tạo gen đánh giá tệp tạm thời một lần mỗi giờ hoặc xóa tệp khi mục nhập trong DB được sửa đổi? Bạn có cách nào để xác định khi điều này xảy ra không?
  • bạn cũng phải thay đổi mã của bạn, sử dụng các tập tin tạm thời, hoặc tái tạo nó nếu cần thiết
    • nếu bạn có nhiều nơi để modifiy, điều này có nghĩa là một số công việc

BTW: Tôi có dám nói điều gì đó như "eval là điều ác" không?

+0

Tôi xin lỗi nhưng đề xuất của bạn hoàn toàn không liên quan. Tôi đang viết một số phần mềm và tôi đã làm nó để nó chỉ sử dụng các tập tin. Tôi muốn cung cấp một thay thế bằng cách sử dụng một cơ sở dữ liệu cho khi viết các tập tin không phải là một lựa chọn, do đó tôi đã kết thúc với điều này. Tuy nhiên, chúng tôi chỉ nói về một truy vấn db và một câu lệnh eval. Và tốc độ không phải là tất cả những gì xấu: 1: 2 cho bao gồm từ tập tin: bao gồm từ db, 10: 8 cho bao gồm từ db: eval từ db. Dù sao, tôi tự hỏi liệu một bao gồm từ db không được lưu trữ ... Ồ, và lý do tôi đến đây là thiếu bán kết tràng lái xe cho tôi điên – Jasper

+0

OK, sau đó; xin lỗi về điều đó ^^ –

0

này cho phép bạn bao gồm một tập tin giả giấy gói tập tin cho bao gồm đang bật trong 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; 
} 

... Sau đó, bao gồm đó là tập tin. ' Có, điều này cũng sẽ vô hiệu hóa bộ đệm mã hóa opcode, nhưng nó làm cho 'eval' này giống như một bao gồm đối với hành vi.

1

Chỉ có eval('?>' . file_get_contents('external.php')); biến thể là thay thế chính xác để bao gồm.

Xem xét nghiệm:

<?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;')); 

Output:

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

Theo ghi nhận của @bwoebi trong this answer to my question, các eval thay không tôn trọng bối cảnh đường dẫn tập tin của tập tin bao gồm. Là một trường hợp thử nghiệm:

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"; 

Kết quả thực hiện php Foo.php:

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

Tôi không biết cách nào để thay đổi __FILE__ hằng số và bạn bè trong thời gian chạy, s o Tôi không nghĩ có cách chung nào để xác định include theo điều khoản của eval.

0

đây là cách tiếp cận của tôi.

nó tạo tệp php tạm thời và bao gồm nó.

nhưng cách này nếu mã bạn muốn chạy trên chức năng này có thoát khỏi chương trình lỗi trước khi tháo tạm thời tập tin

vì vậy tôi thực hiện một thủ tục autoclean trong chức năng. theo cách này, nó sẽ xóa các tệp tạm thời cũ bằng một hàm hết thời gian chờ chạy. bạn có thể đặt thời gian chờ hoặc tắt tính năng này từ các tùy chọn khi bắt đầu chức năng

tôi cũng thêm tùy chọn lỗi bỏ qua để giải quyết các tệp tạm thời không bị xóa. nếu lỗi bị bỏ qua, chương trình sẽ tiếp tục và xóa tệp tạm thời.

cũng một số dự án phải vô hiệu hóa autoclean vì nó quét toàn bộ thư mục mọi lúc nó chạy. nó có thể làm tổn thương hiệu suất đĩa.

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; 

} 
Các vấn đề liên quan