Kepp the following Quote in mind:
If eval() is the answer, you're almost certainly asking the
wrong question. -- Rasmus Lerdorf, BDFL of PHP
(PHP 4, PHP 5, PHP 7, PHP 8)
eval — Exécute une chaîne comme un script PHP
Évalue le code
fourni comme étant du code PHP.
Le code en cours d'évaluation hérite de la portée des variables de la ligne sur laquelle l'appel à eval() a lieu. Toutes les variables disponibles à cette ligne seront accessibles en lecture et modification dans le code évalué. Cependant, toutes les fonctions et classes définies seront définies dans l'espace de noms global. En d'autres termes, le compilateur considère le code évalué comme s'il s'agissait d'un fichier inclus séparé.
La construction de langage eval() est très dangereuse car elle autorise l'exécution de code PHP arbitraire. Son utilisation est vivement déconseillée. Si vous avez soigneusement vérifié qu'il n'y a pas d'autres options que de l'utiliser, gardez une attention toute particulière à ne pas y passer de données provenant d'un utilisateur sans les avoir précédemment validées minutieusement.
code
Code PHP valide à évaluer.
Le code ne doit pas être entouré de
balises PHP
ouvrante et fermante, i.e. 'echo "Hi!";'
doit être passé au lieu de
'<?php echo "Hi!"; >'
.
Il est toujours possible de quitter et de retourner en mode PHP
en utilisant les balises PHP appropriées, i.e.
'echo "En mode PHP !"; ?>En mode HTML !<?php echo "Retour en mode PHP !";'
.
Mis à part cela, le code PHP passé doit être valide. Ceci inclut que toutes les
instructions doivent se terminer par un point-virgule.
'echo "Hi!"'
par exemple résultera en une erreur fatale, alors que
'echo "Hi!";'
fonctionnera.
Une instruction return
terminera immédiatement l'évaluation du code.
Le code sera exécuté dans le scope du code appelant la fonction eval(). Aussi, toutes les variables définies ou modifiées dans l'appel à la fonction eval() resteront visibles après la fin de l'exécution de la fonction.
eval() retourne null
sauf si
return
est appelé dans le code évalué,
auquel cas la valeur passée à return
est retournée. À partir de PHP 7, s'il y a une erreur de syntaxe dans
le code évalué, eval() lance une exception ParseError.
Avant PHP 7, dans ce cas eval() retourne false
et l'exécution du code suivant continue normalement. Il
n'est pas possible d'attraper l'erreur d'analyse de la
fonction eval() en utilisant la fonction
set_error_handler().
Exemple #1 Exemple avec eval() - concaténation de texte
<?php
$string = 'tasse';
$name = 'café';
$str = 'Ceci est une $string avec mon $name dedans.<br />';
echo $str;
eval( "\$str = \"$str\";" );
echo $str;
?>
L'exemple ci-dessus va afficher :
Ceci est une $string avec mon $name dedans. Ceci est une tasse avec mon café dedans.
Note: Comme ceci est une structure du langage, et non pas une fonction, il n'est pas possible de l'appeler avec les fonctions variables ou arguments nommés.
Comme pour toutes les fonctions qui affichent directement des résultats au navigateur, les fonctions de gestion des sorties peuvent être utilisées pour capturer la sortie de cette fonction et l'enregistrer dans une chaîne de caractères (par exemple).
Note:
Dans le cas d'une erreur fatale dans le code évalué, l'ensemble du script se terminera.
Kepp the following Quote in mind:
If eval() is the answer, you're almost certainly asking the
wrong question. -- Rasmus Lerdorf, BDFL of PHP
Inception with eval()
<pre>
Inception Start:
<?php
eval("echo 'Inception lvl 1...\n'; eval('echo \"Inception lvl 2...\n\"; eval(\"echo \'Inception lvl 3...\n\'; eval(\'echo \\\"Limbo!\\\";\');\");');");
?>
At least in PHP 7.1+, eval() terminates the script if the evaluated code generate a fatal error. For example:
<?php
@eval('$content = (100 - );');
?>
(Even if it is in the man, I'm note sure it acted like this in 5.6, but whatever)
To catch it, I had to do:
<?php
try {
eval('$content = (100 - );');
} catch (Throwable $t) {
$content = null;
}
?>
This is the only way I found to catch the error and hide the fact there was one.
If you want to allow math input and make sure that the input is proper mathematics and not some hacking code, you can try this:
<?php
$test = '2+3*pi';
// Remove whitespaces
$test = preg_replace('/\s+/', '', $test);
$number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
$functions = '(?:sinh?|cosh?|tanh?|abs|acosh?|asinh?|atanh?|exp|log10|deg2rad|rad2deg|sqrt|ceil|floor|round)'; // Allowed PHP functions
$operators = '[+\/*\^%-]'; // Allowed math operators
$regexp = '/^(('.$number.'|'.$functions.'\s*\((?1)+\)|\((?1)+\))(?:'.$operators.'(?2))?)+$/'; // Final regexp, heavily using recursive patterns
if (preg_match($regexp, $q))
{
$test = preg_replace('!pi|π!', 'pi()', $test); // Replace pi with pi function
eval('$result = '.$test.';');
}
else
{
$result = false;
}
?>
I can't guarantee you absolutely that this will block every possible malicious code nor that it will block malformed code, but that's better than the matheval function below which will allow malformed code like '2+2+' which will throw an error.
It should be noted that imported namespaces are not available in eval.
imo, this is a better eval replacement:
<?php
function betterEval($code) {
$tmp = tmpfile ();
$tmpf = stream_get_meta_data ( $tmp );
$tmpf = $tmpf ['uri'];
fwrite ( $tmp, $code );
$ret = include ($tmpf);
fclose ( $tmp );
return $ret;
}
?>
- why? betterEval follows normal php opening and closing tag conventions, there's no need to strip `<?php?>` from the source. and it always throws a ParseError if there was a parse error, instead of returning false (note: this was fixed for normal eval() in php 7.0). - and there's also something about exception backtraces
The following code
<?php
eval( '?> foo <?php' );
?>
does not throw any error, but prints the opening tag.
Adding a space after the open tag fixes it:
<?php
eval( '?> foo <?php ' );
?>