Solución al error PHP: «The e modifier is no longer supported» PHP
El modificador e
, correspondiente a la constante PCRE PREG_REPLACE_EVAL
, era utilizado en expresiones regulares junto a la función preg_replace()
cuando era necesario ejecutar PHP para generar el string de salida.
Para hacer su trabajo, el modificador e
echaba mano de la función eval()
, una función muy delicada en lo que a seguridad se refiere, y por ello el modificador e
fue deprecidado en PHP 7. En su lugar se recomienda utilizar preg_replace_callback()
, ya que nos permite definir un callback propio donde podemos ejecutar PHP si es necesario, pero sin necesidad de recurrir a eval()
.
¿Por qué ha sido depreciado?
Vamos a ver un sencillo ejemplo para explicarlo; imaginemos esta expresión donde pasamos un título a letras mayúsculas aplicando la función strtoupper()
al string de salida de preg_replace()
:
$title = "<h1>The /e modifier</h1>";
$title = preg_replace(
'#<h([1-6])>(.*?)</h\1>#e',
'"<h$1>" . strtoupper("$2") . "</h$1>"',
$title
);
Lo que hace preg_repalce()
es:
- Busca el patrón definido en la expresión regular (primer parámetro) en la variable
$title
- Captura los fragmentos que coincidan con los conjuntos entre paréntesis:
([1-6])
y(.*?)
, y los numera por orden de aparición: 1, 2, etc (0 sería la coincidencia completa). - Duelve el string del segundo parámetro sustituyendo las referencias
$1
,$2
, etc, por los correspondientes valores capturados en el paso anterior.
Si observamos el string de salida, podemos ver que se ejecuta una función, strtoupper()
, pero la función está contenida en un string. Para que funciones PHP contenidas en un string sean ejecutadas, hay que pasar ese string a la funcnón eval()
, y eso es lo que hace el modificador e
.
Imaginemos ahora el mismo código pero tomando el valor de $title
desde un input:
$title = $__GET['title'];
$title = preg_replace(
'#<h([1-6])>(.*?)</h\1>#e',
'"<h$1>" . strtoupper("$2") . "</h$1>"',
$title
);
Si el usuario introduce código PHP en el string de entrada, ese código sería ejecutado debido al uso que comentábamos de la función eval()
. Es un punto débil de seguridad, ese es el motivo por el que el modificador e
fue depreciado en PHP 7, y motivo por el que la propia función eval()
se debe utilizar con muchísima precaución.
Alternativa: preg_replace_callback()
Para conseguir el mismo resultado que con preg_replace()
y el modificador e
, pero sin el riesgo de utilizar eval()
, se puede utilizar preg_replace_callback()
, función que nos permite definir un callback propio dónde podemos manejar los valores capturados y generar el string de salida como deseemos, incluyendo la ejecución de código.
El ejemplo anterior quedaría:
$title = $__GET['title'];
$title = preg_replace_callback(
'#<h([1-6])>(.*?)</h\1>#',
function ( $matches ) {
$output = '<h' . $matches[1] . '>' . strtoupper( $matches[2] ) .'</h' . $matches[1] . '>';
return $output;
},
$title
);
O un poco mejor:
$title = $__GET['title'];
$title = preg_replace_callback(
'#<h([1-6])>(.*?)</h\1>#',
function ( $matches ) {
$output = '<h%1$d>%2$s</h%1$d>';
return sprintf(
$output,
$matches[1],
strtoupper( $matches[2] )
);
},
$title
);
En pocas palabras, si se necesita ejecutar PHP en el string de salida de preg_replace()
, hay que utilizar preg_replace_callback()
.
En versiones inferiores a PHP 7 se puede utilziar preg_replace()
y el modificador e
, funcionará, pero por ser un potencial agujero de seguridad, mejor utilizar preg_replace_callback()
incluso en versiones inferiores a PHP 7.