¿Cuándo eval es malo en php?
En todos los años que llevo desarrollando en PHP, siempre he escuchado que usarlo eval()
es malo.
Teniendo en cuenta el siguiente código, ¿no tendría sentido utilizar la segunda (y más elegante) opción? Si no, ¿por qué?
// $type is the result of an SQL statement, e.g.
// SHOW COLUMNS FROM a_table LIKE 'a_column';
// hence you can be pretty sure about the consistency
// of your string.
$type = "enum('a','b','c')";
// option one
$type_1 = preg_replace('#^enum\s*\(\s*\'|\'\s*\)\s*$#', '', $type);
$result = preg_split('#\'\s*,\s*\'#', $type_1);
// option two
eval('$result = '.preg_replace('#^enum#','array', $type).';');
Sería cauteloso al llamar a eval() pura maldad. La evaluación dinámica es una herramienta poderosa y, en ocasiones, puede salvar vidas. Con eval() se pueden solucionar las deficiencias de PHP (ver más abajo).
Los principales problemas con eval() son:
- Posible entrada insegura. Pasar un parámetro que no es de confianza es una forma de fallar. A menudo no es una tarea trivial asegurarse de que un parámetro (o parte de él) sea totalmente confiable.
- Trampa. El uso de eval() hace que el código sea inteligente y, por lo tanto, más difícil de seguir. Para citar a Brian Kernighan " Depurar es dos veces más difícil que escribir el código en primer lugar. Por lo tanto, si escribes el código lo más inteligentemente posible, por definición, no eres lo suficientemente inteligente como para depurarlo " .
El principal problema con el uso real de eval() es sólo uno:
- Desarrolladores inexpertos que lo utilizan sin la suficiente consideración.
Como regla general tiendo a seguir esto:
- A veces eval() es la única solución o la correcta.
- En la mayoría de los casos uno debería probar algo más.
- Si no está seguro, vaya a 2.
- De lo contrario, tenga mucho, mucho cuidado.
eval es malo cuando existe sólo la más mínima posibilidad de que la entrada del usuario esté incluida en la cadena evaluada. Cuando realiza una evaluación sin contenido proveniente de un usuario, debe estar seguro.
Sin embargo, deberías pensarlo al menos dos veces antes de usar eval, parece engañosamente simple, pero teniendo en cuenta el manejo de errores (ver el comentario de VBAssassins), la depuración, etc., ya no es tan simple.
Entonces, como regla general: olvídalo. Cuando eval es la respuesta, probablemente estés haciendo la pregunta equivocada. ;-)
eval es igualmente "malvado" en todo momento.
Si lo ves como algo malo, entonces será igualmente malo en todo momento. Las razones por las que muchos lo describen como malvado no desaparecen con el contexto.
Usar eval() es generalmente una mala idea porque disminuye la legibilidad del código, afecta la capacidad de predecir la ruta del código antes del tiempo de ejecución (lo que tiene posibles implicaciones de seguridad) y, por lo tanto, afecta la capacidad de analizar y depurar código. El uso de eval() también puede evitar que el código evaluado y el código que lo rodea se optimicen mediante un caché de código de operación como Zend Opcache integrado en PHP 5.5 y superior, o mediante un compilador JIT como el de HHVM.
Además, no existe ninguna situación en la que sea absolutamente necesario utilizar eval(): PHP es un lenguaje de programación totalmente capaz sin él. Independientemente de para qué desee utilizar eval(), habrá otra forma de hacerlo, en PHP.
Depende de usted si realmente los ve o no como males o si puede justificarlos personalmente usando eval(). Para algunos, los obstáculos son demasiado grandes como para justificarlos, y para otros, eval() es un atajo útil.
En este caso, eval probablemente sea lo suficientemente seguro, siempre y cuando un usuario nunca pueda crear columnas arbitrarias en una tabla.
Aunque en realidad no es más elegante. Esto es básicamente un problema de análisis de texto, y abusar del analizador de PHP para manejarlo parece un poco complicado. Si desea abusar de las funciones del lenguaje, ¿por qué no abusar del analizador JSON? Al menos con el analizador JSON, no hay ninguna posibilidad de inyección de código.
$json = str_replace(array(
'enum', '(', ')', "'"), array)
'', '[', ']', "'"), $type);
$result = json_decode($json);
Una expresión regular es probablemente la forma más obvia. Puede utilizar una única expresión regular para extraer todos los valores de esta cadena:
$extract_regex = '/
(?<=,|enum\() # Match strings that follow either a comma, or the string "enum("...
\' # ...then the opening quote mark...
(.*?) # ...and capture anything...
\' # ...up to the closing quote mark...
/x';
preg_match_all($extract_regex, $type, $matches);
$result = $matches[1];