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
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.
Checks¶
You can read more about the different checks that PHP Scrutinizer is performing in our dedicated section:
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();
Framework-Specific Guides¶