2009-07-26 6 views
13

Если код такой же, как представляется, разница между:PHP: Эквивалент включают использование Eval

include 'external.php';

и

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

В чем разница? Кто-нибудь знает?


Я знаю, что две разные, потому что include работает отлично и eval выдает ошибку. Когда я изначально задал вопрос, я не был уверен, что он дал ошибку во всем коде или просто на моем (а потому, что код был eval ed, было очень сложно выяснить, что такое ошибка). Однако, после исследования ответа, выясняется, что независимо от того, получаете ли вы ошибку, не зависит от кода в external.php, но зависит от ваших настроек php (точнее, short_open_tag).

+1

Спасибо за этот вопрос. Это помогло: https://github.com/tedivm/Stash/pull/135 – CMCDragonkai

ответ

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;'); 
+0

спасибо за трюк с запятой, это заставило меня с ума! – amrtn

+1

не является eval ("?>". File_get_contents ('external.php')); то же самое, что и include' external.php; ?? –

+0

Юрий Коловский, вы правы, оставляя тег открытия PHP, является альтернативой следованию за ним с точкой с запятой. – Jasper

6

AFAIK вы не можете использовать ускорители php, если используете eval().

+3

AFAIK у вас должен быть реальный файл в файловой системе. – niteria

+0

... и вы не должны беспокоиться об этом, если у вас нет проблемы с производительностью. – niteria

+0

Я имел в виду, что AFAIK php-ускорители работают только с реальными файлами в файловой системе. Построение для php-ускорителей, скорее всего, усложнит ваш код (вы должны проверить, доступны ли файлы для записи и т. Д.), И, возможно, это не сделало бы видимых улучшений. Если они всего лишь файлы шаблонов, я предполагаю, что это ничего не изменит. – niteria

5

Если вы используете веб-сервер, на котором вы установили кеш-код операции, например APC, eval не будет "наилучшим решением": код eval'd не хранится в кэше операций, если я правильно помню (и другой ответ сказал то же самое, кстати).

Раствор можно использовать, по крайней мере, если код не часто меняется, это получить сочетание кода, хранящегося в базе данных и включен код:

  • при необходимости выборки кода из БД, и магазин это в файле на диске
  • включить этот файл
  • как код теперь в файле на диске, кэш опкод будет иметь возможность кэшировать - что лучше для выступлений
  • и вам не нужно будет делать запрос к БД каждый раз, когда вам нужно выполнить код.

Я работал с программным обеспечением, использующим это решение (файл на диске был не более чем кешем кода, хранящимся в БД), и я работал не так уж плохо - лучше, чем при загрузке DB запросы на каждой странице, во всяком случае ...

Некоторые не очень хорошие вещи, как следствие:

  • вы должны получать код с БД, чтобы поместить его в файл «при необходимости»
    • Это может означать повторный ген оценивать временный файл один раз в час или удалять его при изменении записи в БД? У вас есть способ определить, когда это произойдет?
  • вы также должны изменить код, чтобы использовать временный файл, или повторно сгенерировать его при необходимости
    • если у вас есть несколько мест modifiy, это может означать какую-то работу

ОТВЕТ: Я бы осмелился сказать что-то вроде «eval is evil»?

+0

Прошу прощения, но ваше предложение совершенно не имеет значения. Я пишу какое-то программное обеспечение, и я сделал это так, чтобы он использовал только файлы. Я хотел бы предоставить альтернативу с помощью базы данных, поскольку при записи файлов это не вариант, поэтому я закончил с этим. Однако мы говорим только об одном запросе db и одном выражении eval. И скорость не так уж плоха: 1: 2 для include из файла: include from db, 10: 8 для include from db: eval from db. Во всяком случае, я задаюсь вопросом, получает ли include из db кеширование ... О, и причина, по которой я пришел сюда, заключалась в том, что отсутствующая полуколона меня сбила с ума – Jasper

+0

Хорошо, тогда; извините за это ^^ –

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

Как отметил @bwoebi в this answer to my question, подмена 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 Не думаю, что существует общий способ определения include с точки зрения eval.

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; 

}