PHP Scrutinizer

PHP Scrutinizer is the most advanced static analysis engine that is available for PHP code. It goes beyond simple style checks for whether you make use of certain language features. We track how data flows through your application to detect security issues, bugs, unused code, and much more.

Configuring PHP Scrutinizer

You can enable the analysis in your configuration as follows:

build:
    nodes:
        analysis:
            tests:
                override:
                    - php-scrutinizer-run
Note: If you are currently using our legacy PHP analysis, you can learn more about the difference between old and new analysis in our migration guide.

List Dependency Paths

By default, Scrutinizer will inspect all files in your project directory. This might include files which you installed (f.e. dependencies). You can fine tune them using the filter configuration:

filter:
    excluded_paths:
        - "tests/"
        # Everything in a root level "tests" directory will be excluded
    dependency_paths:
        - "lib/"
        # Everything in a root level "lib" directory will be excluded from analysis
        # but treated as a dependency

Note that already excluded dependencies according to our filter guide (or guide to exclude dependencies for older analysis version respectively) should be moved to dependency_paths in the filter configuration.

Controlling Analysis Speed

If you analyze a large project with thousands of files, there are a few ways to speed up the analysis:

1) Reducing the scope of the analysis

You can move some of the files to dependency paths as documented above. This will prevent the analysis from searching for issues in those files, but at the same time, the analysis will still be aware of any classes or functions that are defined there and potentially used by other parts of your code.

This option usually makes sense if you embed dependencies in your project and not for code that you actively develop.

2) Splitting the analysis for monolithic projects

If you have a large monolithic project which contains multiple independent sub-projects, you can split the analysis of those sub-projects. This usually increases the analysis speed.

When running php-scrutinizer-run simply append the sub-project path that should be analyzed:

build:
  nodes:
    analysis:
      tests:
        override:
          - php-scrutinizer-run --sub-project-dir=foo-service/
          - php-scrutinizer-run --sub-project-dir=bar-service/

In the example above, we assume that you have two independent projects. One located in the folder foo-service/ and another one located in the folder bar-service/.

When using the notation above, your filter still has to include all paths relative to the repository root directory. For the example above, the corresponding filter could look like this:

filter:
  paths:
    - "*service/src/*"

3) Increasing the number of CPU cores

By default, the analysis environment runs with a single CPU core. You can increase that number and the analysis will automatically take advantage of additional cores and parallelize the different internal tasks. This can be done in your configuration as follows:

build:
    nodes:
        analysis:
            resources:
                cpus: 4

With the above configuration, the analysis would use 4 CPU cores.

Note: The maximum number of CPUs you can use is equal to the number of containers your subscription has. If you only have a single container in your subscription, you can only use a single CPU for the analysis.

Checks

You can read more about the different checks that PHP Scrutinizer is performing in our dedicated section:

Learn more about PHP Scrutinizer Checks

Security Analysis

The security analysis can take considerable amount of time. Usually, the security analysis takes about as long as all other analysis tasks combined or more. As such, we currently do not enable it by default, but you can turn it on as follows in your configuration:

build:
    nodes:
        analysis:
            project_setup:
                override: true
            tests:
                override:
                    - php-scrutinizer-run --enable-security-analysis

You might have heard about security analysis at other services. Most of the time, this means that those services check your dependencies against a database of known security vulnerabilities, or that they raise issues if you use certain language features like eval that have a tendency to introduce security issues, but without checking if a vulnerability is actually introduced in this specific situation.

Scrutinizer's security analysis however tracks request data coming from $_GET or other request abstractions, and tries to find a path from the request data to a potentially vulnerable sink like eval or echo or mysqli_query. In total, Scrutinizer checks for over 300 of such sinks.

While tracking the data, Scrutinizer also considers whether the data has been escaped and for which contexts it has been escaped. For example, data could be escaped by casting such as (integer)$_GET['page'] or it could be a custom function such as mysql_escape_string($_GET['page']). While (integer)$_GET['page'] generally makes data safe to use regardless of context, code such as echo mysql_escape_string($_GET['page']) would still introduce vulnerabilities such as cross-site scripting.

Depending on the size of your application code and the number of CPUs you allocate for the analysis, this can take time, and you only might want to manually run this analysis from time to time, but not on each inspection.

Using Annotations to Suppress False-Positives

Scrutinizer now also allows using inline annotation to suppress false-positives in addition to filtering false-positives in the web UI.

@scrutinizer ignore-type

Indicates that the type of the following element will be ignored during the inspection, so the usage of the annotation must be inline before the element. For example:

$bar = 'bar';
$foo = new Foo();
$foo->foo( /** @scrutinizer ignore-type */ $bar);

@scrutinizer ignore-call

Indicates that the following function call will be ignored during the inspection. For example:

class Foo
{
    public function bar() { }
}

$foo = new Foo();
/** @scrutinizer ignore-call */ $foo->bar();

@scrutinizer ignore-unused

This annotation attribute is usually used for ignoring unused parameter checking. For example:

public function foo(/** @scrutinizer ignore-unused */ $a, $b) {
    return $b;
}

@scrutinizer ignore-unhandled

PHP Scrutinizer will raise issue if error control opreator @ is used without error handling. This annotation attribute can be applied to ignore the unhandled error checking. For example:

function foo() {
    $my_file = /** @scrutinizer ignore-unhandled */ @file ('non_existent_file');
}

@scrutinizer ignore-deprecated

Can be applied to ignore deprecated class checking. For example:

/**
 * @deprecated
 */
class IsDeprecatedClass { }

$newClass = /** @scrutinizer ignore-deprecated */ new IsDeprecatedClass();