Cuando (si alguna vez) es eval NO malo?


He oído muchos coloca que PHP eval la función es a menudo no la respuesta. A la luz de PHP 5.3 LSB y cierres nos estamos quedando sin razones para depender de eval o create_function.

Hay cualquier casos concebibles donde eval es el mejor (solo?) respuesta en PHP 5.3?

Esta pregunta es no acerca de si eval es malo en general, como obviamente es ni.

Resumen de las respuestas:

  • Evaluación de expresiones numéricas (u otros subconjuntos "seguros" de PHP)
  • Pruebas unitarias
  • PHP interactivo"shell"
  • Deserialización de confianza var_export
  • Algunos lenguajes de plantillas
  • Crear puertas traseras para administradores y/o hackers
  • Compatibilidad con
  • Comprobación de sintaxis (posiblemente no segura)
 25
Author: Community, 2010-08-17

15 answers

Eric Lippert resume la evaluación en tres entradas de blog. Es una lectura muy interesante.

Por lo que sé, las siguientes son algunas de las únicas razones por las que se utiliza eval.

Por ejemplo, cuando está construyendo expresiones matemáticas complejas basadas en la entrada del usuario, o cuando está serializando el estado del objeto a una cadena para que pueda almacenarse o transmitirse, y reconstituirse más tarde.

 17
Author: Russell Dias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-04 13:08:44

Si estás escribiendo malware y quieres hacer la vida difícil para el administrador del sistema que está tratando de limpiar después de ti. Ese parece ser el caso de uso más común en mi experiencia.

 17
Author: tylerl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-17 06:35:36

El principal problema con eval es que es una puerta de enlace para el código malicioso. Por lo tanto, nunca debe usarlo en un contexto donde pueda ser explotado desde el exterior, por ejemplo, la entrada provista por el usuario.

Un caso de uso válido sería en Frameworks de Burla.

Ejemplo de PHPUnit_Framework_TestCase::getMock()

// ... some code before

    $mock = PHPUnit_Framework_MockObject_Generator::generate(
      $originalClassName,
      $methods,
      $mockClassName,
      $callOriginalClone,
      $callAutoload
    );

    if (!class_exists($mock['mockClassName'], FALSE)) {
        eval($mock['code']);
    }

// ... some code after

En realidad hay muchas cosas sucediendo en el método generate. En términos laymens: PHPUnit tomará los argumentos a generate y creará una plantilla de clase a partir de ella. Entonces eval esa clase plantilla para que esté disponible para la instanciación. El punto de esto es tener TestDoubles para simular dependencias en UnitTests por supuesto.

 8
Author: Gordon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-04 16:49:35

Puede usar eval para crear clases ad-hoc:

function myAutoLoad($sClassName){

   # classic part
   if (file_exists($sClassName.'.php'){

      require $sClassName.'.php';

    } else {

      eval("
            class $sClassName{
                public function __call($sMethod,$aArgs){
                     return 'No such class: ' . $sClassName;
                 }
                }");

    }

} 

Aunque, por supuesto, el uso es bastante limitado (algunos contenedores de API o tal vez DI, marcos de prueba ,Ms que tienen que lidiar con bases de datos con estructura dinámica, áreas de juego de código)

 5
Author: ts.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-06 15:13:09

Si está escribiendo un sitio que interpreta y ejecuta código PHP, como lo haría un shell interactivo.

...

Soy un tipo de sistemas, eso es todo lo que tengo.
 3
Author: Ed S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-17 05:59:40

eval es una construcción que se puede utilizar para comprobar si hay errores de sintaxis.

Digamos que tienes estos dos scripts PHP:

script1.php

<?php
// This is a valid syntax
$a = 1;

script2.php

<?php
// This is an invalid syntax
$a = abcdef

Puede comprobar si hay errores de sintaxis usando eval:

$code1 = 'return true; ?>'.file_get_contents('script1.php');
$code2 = 'return true; ?>'.file_get_contents('script2.php');

echo eval($code1) ? 'script1 has valid syntax' : 'script1 has syntax errors';
echo eval($code2) ? 'script2 has valid syntax' : 'script2 has syntax errors';

A diferencia de php_check_syntax (que está obsoleto y eliminado de todos modos), el código no se ejecutará.

EDITAR:

La otra alternativa (preferida) es php -l. Puede utilizar el solución anterior si no tiene acceso a system () o comandos de ejecución de shell.

Este método puede inyectar clases/funciones en su código. Asegúrese de ejecutar una llamada preg_replace o una namespace antes de hacerlo, para evitar que se ejecuten en llamadas posteriores.

En cuanto al tema de OP: Cuando (si alguna vez) no es eval malo? eval simplemente no es malo. Los programadores son malos por usar eval sin ninguna razón. eval puede acortar su código (evaluación de expresión matemática, por ejemplo).

 3
Author: netcoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-27 00:09:34

He encontrado que hay momentos en que la mayoría de las características de un lenguaje son útiles. Después de todo, incluso GOTO ha tenido sus proponentes . Eval se utiliza en una serie de marcos y se utiliza bien. Por ejemplo, CodeIgniter usa eval para distinguir entre la jerarquía de clases de las implementaciones PHP 4 y PHP 5. Los plugins de blog que permiten la ejecución de código PHP definitivamente lo necesitan (y esa es una característica disponible en Expression Engine, Wordpress y otros). También lo he usado para un sitio web donde una serie de vistas son casi idénticas, pero se necesitaba código personalizado para cada una y crear algún tipo de motor de reglas loco era mucho más complicado y lento.

Aunque sé que esto no es PHP, descubrí que la evaluación de Python hace que la implementación de una calculadora básica sea mucho más simple.

Básicamente, aquí está la pregunta:

  1. ¿Eval hace que sea más fácil de leer? Uno de nuestros principales objetivos es comunicar a otros programadores lo que estaba pasando por nuestro cabeza cuando escribimos esto. En el ejemplo de CodeIgniter está muy claro lo que estaban tratando de lograr.
  2. ¿hay otra manera? Lo más probable es que, si está utilizando eval (o variables variables, o cualquier otra forma de búsqueda de cadenas o sintaxis de reflexión), hay otra manera de hacerlo. ¿Has agotado tus otras opciones? ¿Tiene un conjunto de entrada razonablemente limitado? ¿Se puede usar una instrucción switch?

Otras consideraciones:

  1. ¿Se puede hacer seguro? Ser ¿hay una manera de que una pieza de código extraviada pueda trabajar su camino en la declaración eval?
  2. ¿Puede hacerse consistente? ¿Puede usted, dado un input, producir siempre y consistentemente el mismo output?
 2
Author: cwallenpoole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-09 16:17:02

Una ocasión apropiada (dada la falta de alternativas fáciles) sería cuando los datos confiables se serializaron con var_export y es necesario no serializarlos. Por supuesto, nunca debería haber sido serializado de esa manera, pero a veces el error ya está hecho.

 1
Author: Artefacto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-17 06:22:43

Supongo que se debe usar eval donde el código realmente necesita ser compilado. Me refiero a casos como compilaciones de archivos de plantilla (lenguaje de plantilla en PHP por el bien del rendimiento), compilación de gancho de plugin, compilaciones por razones de rendimiento, etc.

 1
Author: Vladislav Rastrusny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-17 08:52:49

Puede usar eval para crear una configuración para agregar código después de instalar el sistema. Normalmente, si desea cambiar el código en el servidor, tendría que agregar/cambiar los archivos PHP existentes. Una alternativa a esto sería almacenar el código en una base de datos y usar eval para ejecutarlo. Tendrías que estar seguro de que el código añadido es seguro.

Piense en ello como un plugin, solo uno que puede hacer cualquier cosa...

Se podría pensar en un sitio que permitiría a la gente a contribuir fragmentos de código que los usuarios podrían agregar dinámicamente a sus páginas web, sin que persistan el código en el sistema de archivos de los servidores web. Sin embargo, lo que necesitarías es un proceso de aprobación...

 1
Author: Knubo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 22:57:21

Compatibilidad. Es bastante frecuente proporcionar alternativas PHP4. Pero del mismo modo es un posible deseo de emular la funcionalidad PHP5.4 en 5.3, como ejemplo SplString. Mientras que simplemente proporciona dos incluyen variantes (incluir.php4 vs incluir.php5) es frecuente, a veces es más eficiente o legible recurrir a eval ():

 $IMPL_AA = PHP_VERSION >= 5 ? "implements ArrayAccess" : "";
 eval(<<<END
     class BaseFeature $IMPL_AA {

Donde en este caso el código funcionaría en PHP4, pero expondría la API/sintaxis más agradable solo en PHP5. Tenga en cuenta que el ejemplo es ficticio.

 0
Author: mario,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 17:19:35

He usado eval cuando tenía un bot con motor php que se comunicaba conmigo y podía decirle que hiciera comandos a través de EVAL: php commands here. Sigue siendo malo, pero si su código no tiene idea de qué esperar (en caso de que extraiga un trozo de código PHP de una base de datos) eval es la única solución.

 0
Author: Mikhail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 19:35:47

Por lo tanto, esto debería ser cierto para todos los idiomas con eval:

Básicamente, con pocas excepciones, si está construyendo el valor pasado a eval o obteniéndolo de una fuente no verificada, está haciendo algo mal. Lo mismo ocurre si está llamando a eval en una cadena estática.

Más allá de los problemas de rendimiento con la inicialización del analizador en tiempo de ejecución y los problemas de seguridad, generalmente se entromete con el sistema de tipos.

Más en serio, se acaba de demostrar que en el en la gran mayoría de los casos, hay enfoques mucho más elegantes para la solución. Sin embargo, en lugar de prohibir la construcción por completo, es bueno pensar en ello como uno podría goto. Hay usos legítimos para ambos, pero es una buena bandera roja que debería hacerte pensar si estás abordando el problema de la manera correcta.

En mi experiencia, solo he encontrado usos legítimos que caen en las categorías de plugins y usuario privilegiado (por ejemplo, el administrador de un sitio web, no el usuario de tales) extensiones. Básicamente cosas que actúan como código proveniente de fuentes confiables.

 0
Author: Arelius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 23:21:57

No uso directo, pero el modificador /e a preg_replace utiliza eval y puede ser muy útil. Ver ejemplo # 4 en http://php.net/preg_replace .

Si es o no malo/malo es subjetivo y depende completamente de lo que consideres "bueno" en un contexto específico. Cuando se trata de entradas no confiables por lo general se considera malo. Sin embargo, en otras situaciones puede ser útil. Imagine escribir un script de conversión de datos de una sola vez bajo una presión extrema de plazo. En este situación, si la evaluación funciona y hace las cosas más fáciles, tendría problemas para llamarlo mal.

 0
Author: llama,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-09 05:34:03

Este debate de evaluación es en realidad un gran malentendido en el contexto de php. A la gente le encanta pensar que eval es mala, pero por lo general no tienen ningún problema en usar include, aunque incluir es esencialmente lo mismo. Incluir foo es lo mismo que eval file_get_contents foo, por lo que cada vez que incluyes algo cometes el pecado mortal de eval.

 -1
Author: user187291,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-06 04:39:39