2009-07-26 16 views
13

Si el código es el mismo, no parece haber una diferencia entre:PHP: Equivalente de incluir el uso de eval

include 'external.php';

y

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

¿Cuál es la diferencia? ¿Alguien sabe?


sé los dos son diferentes porque el include funciona bien y el eval da un error. Cuando originalmente formulé la pregunta, no estaba seguro de si daba un error en todo el código o solo en el mío (y porque el código era eval ed, era muy difícil averiguar qué significaba el error). Sin embargo, después de haber investigado la respuesta, resulta que si el error se obtiene o no depende del código en el external.php, pero depende de su configuración de php (short_open_tag para ser precisos).

+1

Gracias por esta pregunta. Me ayudó con esto: https://github.com/tedivm/Stash/pull/135 – CMCDragonkai

Respuesta

13

Después de investigar un poco más, descubrí lo que me pasaba. El problema está en el hecho de que <?php es una "etiqueta de apertura breve" y solo funcionará si short_open_tag se establece en 1 (en php.ini o algo con el mismo efecto). La etiqueta correcta completa es <?php, que tiene un espacio después de la segunda p.

Como tal, la propia equivalente de la incluyen es:

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

Alternativamente, puede dejar la etiqueta de apertura a cabo todos juntos (como se señala en los comentarios a continuación):

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

Mi originales solución fue agregar un punto y coma, que también funciona, pero se ve mucho menos limpio si me preguntas:

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

gracias por el truco del punto y coma, ¡me estaba volviendo loco! – amrtn

+1

no es eval ("?>". File_get_contents ('external.php')); lo mismo que incluir 'external.php'; ?? –

+0

YuriKolovsky, tiene razón al omitir la etiqueta php-opening es una alternativa para seguir con un punto y coma. – Jasper

6

AFAIK no puede aprovechar los aceleradores php si usa eval().

+3

AFAIK tienes que tener un archivo real en el sistema de archivos. – niteria

+0

... y no debería preocuparse, a menos que tenga un problema de rendimiento. – niteria

+0

Quise decir que los aceleradores AFAIK php solo funcionan con archivos reales en el sistema de archivos. La construcción de aceleradores de PHP probablemente complicará su código (debe verificar si los archivos son escribibles, etc.) y es posible que no mejore de forma visible. Si solo son archivos de plantilla, supongo que no cambiará nada. – niteria

5

Si está utilizando un servidor web en el que ha instalado un caché de código de operación, como APC, eval no será la "mejor solución": el código eval'd no se almacena en el caché del código de operación, si recuerdo correctamente (y otra respuesta dijo lo mismo, por cierto).

Una solución podría utilizar, al menos si el código no se cambia con frecuencia, es obtener una mezcla de código almacenado en la base de datos y que incluyan código:

  • cuando sea necesario, ir a buscar el código de la base de datos, y almacenar en un archivo en el disco
  • incluir ese archivo
  • como el código se encuentra ahora en un archivo, en el disco, caché de código de operación será capaz de almacenar en caché - que es mejor para actuaciones
  • y no será necesario para hacer una solicitud al DB cada vez que tenga que ejecutar el código.

He trabajado con un software que usa esta solución (el archivo en el disco no es más que un caché del código almacenado en DB), y no funcionó tan mal, mucho mejor que hacer un montón de solicitudes de base de datos de cada página, de todos modos ...

Algunas cosas no tan buenas, como consecuencia:

  • usted tiene que buscar el código de la base de datos para ponerlo en el archivo "cuando sea necesario"
    • esto podría significar re-gene clasificando el archivo temporal una vez por hora, o eliminándolo cuando se modifica la entrada en DB? ¿Tienes una forma de identificar cuándo sucede esto?
  • también tiene que cambiar su código, para utilizar el archivo temporal, o volver a generarlo si es necesario
    • si tiene varios lugares para actualiza, esto podría significar un trabajo

Por cierto: ¿me atrevería a decir algo así como "eval is evil"?

+0

Lo siento, pero su sugerencia es completamente irrelevante. Estoy escribiendo un software y lo hice para que solo use archivos. Quería proporcionar una alternativa mediante el uso de una base de datos para cuando escribir archivos no es una opción, así que terminé con esto. Sin embargo, solo estamos hablando de una consulta db y una declaración eval. Y la velocidad no es tan mala: 1: 2 para incluir desde el archivo: incluir desde db, 10: 8 para incluir desde db: eval desde db. De todos modos, me pregunto si una inclusión de db se almacena en caché ... Oh, y la razón por la que vine aquí fue que falta el punto y coma me está volviendo loco – Jasper

+0

OK, entonces; perdón por eso ^^ –

0

Esto le permite incluir un archivo asumiendo envoltorios de archivos solicita comprenda está activado en 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; 
} 

... Entonces que incluyen 'archivo'. Sí, esto también desactivará los cachés de opcode, pero hace que este 'eval' sea lo mismo que un include con respecto al comportamiento.

1

Sólo la variante eval('?>' . file_get_contents('external.php')); es el reemplazo correcto para incluir.

Ver pruebas:

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

Salida:

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

Como señaló @bwoebi en this answer to my question, la sustitución eval no respeta el contexto de la ruta de archivo del archivo incluido. Como un caso de prueba:

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

El resultado de la ejecución de php Foo.php:

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

no sé de ninguna manera de cambiar el __FILE__ constante y amigos en tiempo de ejecución, s o No creo que haya una forma general de definir include en términos de eval.

0

aquí está mi enfoque.

crea un archivo php temporal y lo incluye.

pero de esta manera si el código que desea ejecutar esta función tiene programa termina errores antes de retirar archivo temporal

así que hago un procedimiento de limpieza automática de la función. de esta forma, limpia los archivos temporales viejos por un tiempo de espera cada vez que se ejecuta la función. puede configurar el tiempo de espera o deshabilitarlo desde las opciones al inicio de la función

También he agregado la opción de ignorar error para resolver archivos temporales no eliminados. si se ignoran los errores, el programa continuará y eliminará el archivo temporal.

También algunos proyectos tienen que deshabilitar la limpieza automática porque escanea todo el directorio cada vez que se ejecuta. podría dañar el rendimiento del disco.

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; 

}