Если код тот же, то существует разница между:
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;');
AFAIK вы не можете использовать ускорители php, если используете eval ().
Если вы используете веб-сервер, на котором вы установили кеш-код операции, например APC , eval
не будет « лучшим решением »: код eval'd не хранится в кеше кода операции, если я правильно помню (и еще один ответ сказал, что то же самое, кстати) .
Решение, которое вы могли бы использовать, по крайней мере, если код не часто изменяется, получает соединение кода, хранящегося в базе данных, и включает код:
Я работал с программным обеспечением, использующим это решение (файл на диске был не более чем кешем кода, хранящимся в БД), и я работал не так уж плохо – лучше, чем при загрузке запросов БД каждой страницы, так или иначе…
Некоторые не очень хорошие вещи, как следствие:
Кстати: я бы смел сказать что-то вроде «eval is evil»?
Как заметил @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
.
Только 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
Это позволяет вам включать файл, предполагающий, что файловые оболочки для включений включены в 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» таким же, как включение в отношении поведения.
вот мой подход.
он создает временный файл 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; }