---
title: "The Land Where PHP Uses eval()"
url: https://www.exakat.io/land-where-php-uses-eval/
date: 2018-10-02
modified: 2023-12-18
author: "dams"
description: "The Land Where PHP Uses eval() It is 2018, and the PHP world useseval() in more than 28% of every PHP code source. It is repeatedly reported as a security..."
categories:
  - "Code auditing"
  - "Technology"
tags:
  - "code audit"
  - "eval"
  - "modernisation"
  - "security"
image: https://www.exakat.io/wp-content/uploads/2018/10/roadwork.320.jpg
word_count: 3215
---

# The Land Where PHP Uses eval()

# The Land Where PHP Uses eval()

It is 2018, and the PHP world uses`eval()` in more than 28% of every [PHP code source](https://www.exakat.io/exakat-coding-index-2018-08/). It is repeatedly reported as a security issue and a performance bottleneck, and a memory hazard. Yet, we can't get rid of it.

It seems reasonable to think that most of `eval` capabilities are available as a PHP features. So, we took examples from 2000 PHP open source projects, and reviewed the situation. Here are real-life examples of `eval` usage : for each of them, we'll discuss the actual replacement.

## JSON decode replacement

This first situation is a light implementation of `json_decode()`. The initial warning says 'enable native json' and that's a good piece of advice. Yet, as of today, the application still uses `dol_json_decode()` in two situations, and some tests.

If we go back to a time where `json_decode()` was not a PHP native function, the code written here is a light alternative. Maybe not complete, but useful in many situations.

To implement the decoding, the JSON is read, tokenized and turned into a PHP code that builds an array. Then, the code is executed, and the array is finally a PHP piece of data, with the help of `eval()`.

Instead of creating PHP code for `eval()`, it would have been better to build the array directly in the main loop. The hard point in this code is when the JSON nests several levels of arrays and objects. This meant recursion, and it was simpler to do with `eval()`.

## Multidimensional array

Here is a situation where the code builds a multidimensional array. Data are read from the database, and a big array of stats is built. And this requires `eval()`.

A list of rows is read from the database, with a simple SELECT query. Each row is passed at the function genSiteStatFile() to build a PHP piece of code. This function relies on an object call : nothing special is done beyond converting a string to a link. The result is a piece of code that represents an array. All those arrays are concatenated in one code, and they make up the final stats.

Given the complexity of the task, the secondary function seems superfluous, and the eval() may very well be skipped to build the stats within PHP.

It would be interesting to check if the secondary function helps manage memory. The code here is not recent, and when the instantiation is in a separate function, this may trigger more often the garbage collector, leading to a lighter process. It may be less impact full with PHP recent improvements.

## Creating missing classes

`Eval()` is used to create whole classes, just like this :

In fact, PHP accepts multiple definitions of classes in the code, and only activates them if the code is executed : this must be interesting to see in the Zend engine. This way, there is no need to create the classes with `eval()`, hard coding them is sufficient.

## Rewriting classes on the fly

This one-line `eval()` is quite impressive in terms of features : the eval is applied to the result of a double-regex call to `preg_replace()`, applied to the imploded lines of a piece of code. The code is so well crafted that not a single verification is needed after several PHP native function calls.

As you can read the regex, it actually replaces a piece of code with another name, on the fly. The original name is extended with `OverrideOriginal_remove` and a unique ID that was built a little before. Just below, another `eval()` with the same syntax loads the same class, but set the name with 'Override_remove' and the same unique ID. Later, with Reflection, the class is stripped of its methods and properties. The resulting code is then stored in a file, for later inclusion (not shown here).

`Eval()` is used here to include two classes with the same name. The initial problem for that piece of code is to load both the classes with the same name and be able to compare them.

Instead of applying preg_replace() to the class definition, it would be better to use a namespace renaming. That way, only `namespace A\B\C` is renamed with `namespace A\B\C\Original`. Then, the code may be loaded with Reflection from two different namespaces, and compared until the final writing.

## Reordering arguments

What to do when you have the right variables, but not in the right format? Write a function that reorganize the arguments so they fit the correct API. This is what this function does :

The objective is to use array_multisort() to sort a multidimensional array. Yet, all the rows are in one array, aka the first argument. So, columns are extracted, sorted in an arbitrary order, and then, applied to the initial array. This is a close cousin to the ORDER BY clause in SQL.

Here, the problem is that the initial data has to be extracted column by column from `$marray`, and then, used at the right place in the call to `array_multisort()`. As you can see, the loop builds a serie of `$sortarray`, which are only referenced in the `$msortline`. Since `eval()` is executing the code in the current context, `$sortarray` will be available, and sorted.

Nowadays, we can use the ellipsis operator `...` or the old-fashioned `call_user_func_array()` : both allows us to prepare the arguments in an array, with total freedom of organization, then submit them to the function.

## Code compatibility

Imagine that your code wants to take advantage of a new PHP feature, from a new PHP version. Classic problems of migration : how to use a feature that is not yet available.

The real challenge appears when the upcoming feature doesn't compile on your current version. For example, imagine a world where PHP has no `clone` operator. This is the case here :

The `clone` call is now in a string, which will only be evaluated if the version is compatible with this operator. Otherwise, the code is ignored, and the `copy` is done with another method. Yet, for this class to compile, `clone` must be avoided in the code, which is the case here.

This strategy allows old code to run new syntax, preparing for migration. Any speed gain related to a native `clone` operator is probably offset by the `eval` code and the static method call. Yet, this allows for cross version compatibility. The most important here is to remember to remove this piece of code once the older version has been totally abandoned.

This usage of `eval` may be the cleverest we have reviewed so far. We found situations where `clone` and `instanceof` have been protected that way.

Note also that this may be valid for backward compatibility. PHP 7 abandoned dynamic global variable, and this is a patch for compatibility.

## Escaping the sequence

This piece of code makes a clever usage of PHP's escape sequences. This one is the hexadecimal format for characters : `\xhh`, where hh is hexadecimal characters.

`$dtime` collects the time in a Dos format, then turns it into a hexadecimal string. Then, the hexadecimal time is crafted by inverting the order of the hexadecimal chars from the `$dtime`string. Note that is still a string, yet it is used with an array syntax.

`\xhh` may be replaced by `chr(hexdec())` call. `chr` produces a character from its ASCII representation. This representation needs to be decimal, but extracting the correct digits from `$dtime` has to be done with hexadecimal format. So, we both need `dechex` and `hexdec`to finish the calculation correctly.

Although it is longer to write, `chr` is 4 times faster than `eval`.

## Dynamic variabling

One recurring usage of `eval` is the emulation of the variable variable. If `$$var` is a well-known situation, there are some tricky issues to solve. For example :

This happens when the code knows which variable to use, but doesn't know yet the value. Here is one :

`$str2` string contains a variable, and it should be replaced with another value, from another source. For this illustration, the code is simplified, but that kind of on-the-fly replacement is often done after a long list of expressions.

Note also that `eval` only execute PHP code. There does not need for the opening tags`';`

Back to the initial expression. `eval` is used here for replacement : the value is in the `name`variable, and the incoming argument is a kind of a template. The secure way to do this is to use `str_replace`, or `preg_replace`, or `preg_replace_callback`. The incoming template is used as a piece of data, and not executed as a piece of code.

Here is another example of such templating, with a database storage. The address format is stored in the database, as a piece of code : you can see the variable names, which will be taken from executing context.

`eval` could be replaced here with a single `str_replace` call :

## Dynamic new call

One classic build of class name for instantiation.

`new` accepts variables for instantiation, so in the first example, `eval` is not needed. As for the second, `new` doesn't accept expressions, so it needs a workaround to create a dynamic name. Here,

## Evaluating math or logical expression

`eval` may be used to execute a subset of PHP functionalities. In particular, math expressions may be written by the user, and executed by PHP.

`$option` contains a math expression, with its specific format. The values are collected from another source, and this `eval` executes it.

You'll be pleased to see that the `eval` is already targeted for elimination. But it has not been removed yet, for a good reason : the alternative requires a lot of work.

Coding math in PHP is easy : many operators are available, and parentheses, and precedence, and so are constant and functions. Thus, it is tempting to harness this power by running the expression as a string in eval(), along with the values.

The sane replacement is to use a math-parser component. For example, [math-parser](https://packagist.org/packages/mossadal/math-parser), or [php-math-parser](https://github.com/ircmaxell/php-math-parser.git). For logical expressions, there is the [expression language](https://symfony.com/doc/current/components/expression_language.html) from Symfony.

Yet, replacing what looks like a small string, by a full-blown PHP component, spread over several classes is quite scary. The alternative is to filter the string thoroughly : accepting numbers, operators, parentheses and its nesting, and a few functions like log(), e() etc. There is feature creep written all over this possibility, and it will probably end up as a full-blown component, spread over several classes.

## Evaluating a PHP expression

Quite obvious, right? This situation arises when a framework allows PHP code to be executed as part of its own process. For example, you may include PHP expression inside a PDF, ODT or XML template, or run customisation for an HTML tag. Since those are left to the developer, there is a need for PHP code to be written in one part of the source, and executed somewhere else.

This is how methods like this one are written :

`evaluateExpression` is nothing more than a glorified `eval` call : arguments are coming in one array, and are later `extract`()-ed, so they end up in the current context. Then, the PHP code, written in `$_expression_` is executed. Note the prefixed `return` that is necessary to get the value from the `eval`, unless it is assigned to a local variable. Separation of context is difficult here.

The whole method looks like a function call : the body of the function is `$_expression_`, and the arguments are in `$data`. Actually, this is exactly how `create_function` works :

First, note that arguments and code are swapped. But they are both the same arguments as for `evaluateExpression()`.

`$args` is a list of arguments names : it may be extracted from `$data` with `array_keys()`: `$args = implode(', ', array_keys($data));`, which will produce something like `$a, $b, $c`.

The result of `create_function()` is a string, that represents an anonymous function. It may be used later just like any function, with the values of the `$data` variable : `$result = $anonymousFunction(...array_values($data));`.

As the manual mentions it, `create_function()` is a bad idea : 'This function internally performs an eval() and as such has the same security issues as eval(). Additionally it has bad performance and memory usage characteristics.'

Besides, `create_function()` is deprecated since PHP 7.2, and it is replaced by the [Closures](http://php.net/manual/en/functions.anonymous.php). The syntax is very close to the `create_function`, and a lot more elegant :

Now, the result is a `Closure` object, which acts as a function (and more). In particular, in the context that we are studying, the closure may be written in one part of the framework, like in a custom module, handed to the framework, and transmitted until it is executed. This approach has the benefit of PHP opcodes, as the code is compiled before execution.

There is a last case that closure can't cover : `create_function` used to allow function creation with codes submitted by the user. Closure require hardcoded code, so this use case is forbidden. For security reasons, it is actually a major upgrade. And that leaves very little situations where the `eval()` is useful to execute random PHP code, except maybe [3v4l.org](http://www.3v4l.org/).

## Final weird stuff

All the above are real examples, extracted from the real code. Those make sense, even when there are alternative names. Here are a few other situations, which are plain weird.

## Little reasons for code that uses eval()

I started this journey with the firm belief that `eval` shows a lack for knowledge with PHP. All the situations we have detailed together, with the exceptions of three, have a corresponding PHP alternative that is better and more elegant.

- Early `json_decode()` : recursion
- Multidimensional array: direct PHP code
- Creating missing class : use namespaces
- Reordering arguments : use ... or call*user*func_array()
- Dynamic variabling : use PHP dynamic syntax
- Escaping the sequence : use chr() and dechex()

The valid reasons :

- Code compatibility workaround : valid for transition, and so rare
- Evaluating math or logical expression : the alternative is more than a few lines of code, and yet...
- New dynamic instantiation : PHP could improve this syntax

My last question would be this : can we lint PHP code from PHP code ? Currently, lint must be run as an external program. And there is no way to compile PHP code from within PHP itself, without relying on eval() and its try/catch, with the threat that any injection will takeover the whole server. Tokenizing a string is possible, with `[token_get_all](http://www.php.net/token_get_all)()`, though it has no syntax validation. Yet, before running anything through `eval()`, there is no way to check if this run.

 