The /e
modifier is very hard to make safe, and it will be removed in a future version of PHP. The reason is that it performs its substitution first and then evaluates the code (as though with eval()
).
It is therefore possible to craft input such that the substituted code runs arbitrary PHP functions or exposes private variables.
Some escaping is performed automatically, but it is insufficient protection, as shown by this example which executes an arbitrary function using your code and the examples in the PHP manual:
function dangerous()
{
echo 'Dangerous code executed';
}
$arg = '42{${dangerous()}}';
preg_replace("/([0-9]+)(.+)/e",'list($var, $var2) = array("$1", "$2")', $arg);
var_dump($var, $var2);
In contrast, preg_replace_callback()
sends the value of the substitution as a parameter to a callback function, so there is no way for the contents of the initial string to be evaluated directly as code.
Note that in your example, the executed code is just assigning variables anyway, so doesn't need any kind of callback, only to capture the matches with preg_match()
:
preg_match("/([0-9]+)(.+)/", $arg, $matches);
$var = $matches[1];
$var2 = $matches[2];