elk.320Exakat 0.10.6 (immortal elk power) is finally here. The main feature of the major speed increase, so that alone is worth upgrading to this version. In the same time, a lot of ground work has been done, and six new analyzers are made available.

Major speed increase

Two upgrades have been made on the Exakat engine: one at loading time, and one at analysis time.
The loading phase is the one that turns the scripts from a text file into a structured tree in the graph database. It relies on the PHP Tokenizer to get the tokens, then builds the AST (abstract syntactic tree), and resolve as much as possible, like the actual Full Namespace Path, the boolean value or the ‘constant’ expression property.

Most of those are done in one pass: Exakat reads the tokens in order, and then place them directly where they belong, along with all theirs characteristics. The tokens are loaded in the database, and then, a second pass is done. For example, marking a function as ‘PHP native’ function is done during the second phase: exakat needs to know that no function definition is available for the functioncall to make sure this is a PHP function.

We optimized the workload by moving as much as possible from the second pass to the first pass. The second pass cannot be removed: the ‘PHP native’ functions can’t be checked until the whole codebase has been processed. But the less the better.

And the results are in: loading WordPress went down from 7min20s to 3 mins, a rough 50% gain. This means that code is now faster to be loaded, and the first results of analysis may be dumped faster too.

The second upgrade was the usage of gremlin index during the analysis phase. Every time that is can, Gremlin now uses existing index to make the first selection of nodes. The trick is that Gremlin never knows when to use them, as this is an underlying database feature. When it is available, it may cut processing time from 30% to 800%, depending on the queries and the actual data. The speed boost is significant, but may vary quite a lot from projects to projects.

In the end, running audits with exakat has never been so fast. During the course of the last 48 hours, we managed to check over 100 MLOC of PHP on a single server. We’re quite convinced that you’ll feel the gain too!

Of course, we took advantages of the new performances to add more analysis.

Support for Zend-framework 3

We added support for zend-view and zend-mvc, reaching six components out of 60+. For each of the components, exakat now detects their usage (or not), and provides a list of version compatibilities. Based on usage of classes, traits and interfaces, you get a global view of what is needed to keep up with the frenetic pace of Zend Framework.

List of used ZF3 components by Exakat

We also added support for ‘deprecated’ features: any usage of deprecated class, trait, interface, property, constant or method are reported, for all the current list of supported components. This may prove handy to migrate smoothly.

Some classes are missing to ensure the compatibility with Zend-mvc 3.0. Compatibility with zend-validator and zend-view are OK, until most recent versions.

Check all ZF3 versions in one glance

Support for CakePHP from 2.5 to 3.3

Cake PHP now also get support for migration: all classes, interfaces and traits are catalogued, middle version by middle version, and you can get a complete breakdown of incompatible structures with each of them. You’ll see quite a step moving from Cake 2.x to 3.x, but for middle versions, exakat now tracks the tiniest class evolution.

Report missing type tests

Here is a classic piece of testing:

<?php
    function redColorKeyword($text){
        if(is_array($text)) {
            foreach ($text as $key => $value) { /**/ }
        } else {
            $text = str_replace($this->keyword,'<font color="red">'.$this->keyword.'</font>',$text);
        }
        return $text;
    }
?>

If it is an array, treat it like an array (foreach), but otherwise, treat it like a string. Here, the ‘else’ should really be ‘elseif (is_string($text))’. null, boolean, integers and real are indeed processed just like strings. However, $text may end up being an object, or a resource. In that case, a Recoverable fatal error will be raised.
The idea is that a variable is not an array or a non-array. Variables may be one of : null, integer, real, string, array, object, resource. Here, non-array is expected to be ‘string’, and it may not be. For example, is_callable() could be used with ‘else’: a variable is either callable, or not. There are no other possibilities.
The recommended behavior is then to always check for the requested type, and use else to throw an exception.

<?php
function redColorKeyword($text){
        if(is_array($text)) {
            foreach ($text as $key => $value) { /**/ }
        } else if(is_array($text)) {
            $text = str_replace($this->keyword,'<font color="red">'.$this->keyword.'</font>',$text);
        } else {
            throw new \Exception('wrong type for $text');
        }
        return $text;
    }
?>

When checking the type of a variable, ‘else’ should only be used when it doesn’t rely on the tested variable, like throwing an exception, killing the script or returning without processing, overwriting the variable with a default value would all be acceptable behavior. Just like this :

<?php
function redColorKeyword($text){
        if(is_array($text)) {
            foreach ($text as $key => $value) { /**/ }
        } else {
            throw new \Exception('wrong type for $text');
        }
        return $text;
    }
?>

Obviously, the main objection here is that when conception for this code only allows the variable to be one of two types : array or string. Then the extra check is overkill. Indeed, if $text is either array or string, then all is OK. That is probably the efficient way to do it, albeit the lazy one. It definitely saves the extra test.

PHP being dynamic, there is no way to ensure that a variable is only a string or an array. Even typehint won’t help here. Also, and as usual, making the test explicit leads to clearer code, and helps process errors, unexpected situations and a future refactoring. This is robustness in depth, and by experience, it brings more stability at the cost of extra code.

Well, now exakat tracks those situations for us so we can always come back and make the code more robust when it is worth it.

Usage of setcookie()

Two analysis are devoted to setcookie(). One tracks the usage of header() to set cookies: whenever possible, just just setcookie() or setrawcookie() to do so, as it is native, and handles encoding, or not.

Setcookie() also offers five extra parameters to set, so as to raise your cookies security. Even as a simple reminder, they are worth using setcookie() and strengthening the code. The extra parameters are the expiration date, the path of usage, the domain of usage, the protocol of transmission and the accessibility of the cookie to javascript, in that order. Giving a value to every parameter is the best, even if it catch a wide net : better some value than no value.

Do not cast to int

Last rule is a reminder that casting to Integer may behave unexpectedly, depending on the precision in the real numbers. The manual reports: Never cast an unknown fraction to integer, as this can sometimes lead to unexpected results.

<?php
echo (int) ( (0.1+0.7) * 10 ); // echoes 7!
?>

The advice is then to avoid using real numbers in general, or rely on functions like round(), floor() and ceil() to set explicitly the behavior of the casting. Reminder : intval() is the same as (int).

Happy PHP code auditing with exakat 0.10.6

Exakat 0.10.6 comes with a major speed boost that is worth. New analysis are also coming with this version, and a large number of new ideas will be processed in the coming weeks: thanks for your contributions, exakat will soon offer more analysis than ever, and support even more frameworks. Visit the ever-green rule of ‘bail out early‘, one of the 300+ analysis.

Download Exakat on exakat.io, test it online with the free SAAS, upgrade it with ‘exakat.phar upgrade -u’ and like us on github: https://github.com/exakat/exakat.