Php Sat Getting Started

Static analysis for PHP

Analyzing a file

After you have installed php-sat you can run it by typing:
  php-sat -h
If this command does not produce a list of all the options that are available for php-sat you should check your installation.

We will start with a simple file, foo.php that contains an example of the bug-pattern C002:

$ cat foo.php
<?php
  function foo($bar){
     echo $bar;
  }

  foo("param1", "param2");
?>

We can feed this to php-sat by using the -i option (we also use the --extended-output option to show the complete file again):

$ php-sat -i foo.php --extended-output
<?php
  function foo($bar){
    echo $bar;
  }
  /**
   * PHP-SAT check (Correctness)
   * Pattern ID : C002
   * Description: Too many parameters in function call
   */
  foo("param1", "param2");
?>

The output can also be saved into a file by giving the filename to the -o option:

$ ls
foo.php
$ php-sat -i foo.php -o foo.php.php-sat --extended-output
$ ls
foo.php  foo.php.php-sat
$ cat foo.php.php-sat 
<?php
  function foo($bar){
    echo $bar;
  }
  /**
   * PHP-SAT check (Correctness)
   * Pattern ID : C002
   * Description: Too many parameters in function call
   */
  foo("param1", "param2");
?>

Analyzing multiple files

But what if we have this foo-simple.php:
$ cat foo-simple.php
<?php
  include 'foo.inc';
 
  foo("param1", "param2");
?>
this foo-complex.php:
$ cat foo-complex.php
<?php
  $postfix = 'inc';
  include 'foo.'.$postfix;
 
  foo("param1", "param2");
?>
and this foo.inc:
$ cat foo.inc 
<?php
  function foo($bar){
     echo $bar;
  }
?>

The output of php-sat on foo-simple.php would then be:

$ php-sat -i foo-simple.php --extended-output
<?php
  include 'foo.inc';
  foo("param1", "param2");
?>
and on foo-complex.php:
$ php-sat -i foo-complex.php --extended-output
<?php
  $postfix = 'inc';
  include 'foo.' . $postfix;
  foo("param1", "param2");
?>
which is still correct, php-sat only reports things it finds, so reporting nothing is still correct, but we would want php-sat to include the files that are included. There are two modes in which php-sat can include files, simple and complex.

Simple inclusion

Simple inclusion means that php-sat will try to include every file that is included by a literal name. Every include/require/include_once/require_once statement that is followed by a literal string will be included if the file can be found. This mode does not respect the *_once-semantics, nor will it take into account concatenated names.

So the _php-simple.php_-problem can be solved by passing the --simple-inclusion flag to php-sat.

$ php-sat -i foo-simple.php --simple-inclusion --extended-output
<?php
  include 'foo.inc';
  /**
   * PHP-SAT check (Correctness)
   * Pattern ID : C002
   * Description: Too many parameters in function call
   */
  foo("param1", "param2");
?>
This the same output as before, we could even use the -o option is we wanted.

The output for foo-complex.php is still not informative:

$ php-sat -i foo-complex.php --simple-inclusion --extended-output
<?php
  $postfix = 'inc';
  include 'foo.' . $postfix;
  foo("param1", "param2");
?>

Complex inclusion

Complex inclusions is not complex for the user, just for php-sat itself. This mode will trigger constant-propogation which will, as the name implies, propagate constant information through the scripts. This causes the complex mode to use more resources, but enables a larger set of analysis's.

This mode does respect the semantics of the *_once-statements, so files will only be included the first time they are encountered.

The complex mode can be seen as an extension to the simple mode, every file that is included in the simple mode will also be included by the complex mode.

So the output for foo-simple.php with the --complex-inclusion flag will be:

$ php-sat -i foo-simple.php --complex-inclusion --extended-output
<?php
  include 'foo.inc';
  /**
   * PHP-SAT check (Correctness)
   * Pattern ID : C002
   * Description: Too many parameters in function call
   */
  foo("param1", "param2");
?>
and for foo-complex.php:
$ php-sat -i foo-complex.php --complex-inclusion --extended-output
<?php
  $postfix = 'inc';
  include 'foo.' . $postfix;
  /**
   * PHP-SAT check (Correctness)
   * Pattern ID : C002
   * Description: Too many parameters in function call
   */
  foo("param1", "param2");
?>

Printing included files

In real world situation the included files could also contain bug-patterns. These patterns can either be static, always available in the source file, or dynamic, available under certain inclusion-conditions. It is useful to examine the included files after they are included to check for these patterns.
The default behavior for included files is that they are discarded from the memory after the analysis. This behavior can be altered by passing the --print-included-files flag. This flag will print all included files to the same location as the original files, giving them a =php-sat=-postfix.

Here is a little example with simple inclusion. We have the same files as before:

$ ls
foo-simple.php foo-complex.php foo.php foo.inc

When we use php-sat with a target we get one extra file with a result:

$ php-sat -i foo-simple.php -o foo-simple.php.php-sat --simple-inclusion --extended-output
$ ls
foo-simple.php foo-complex.php foo.php foo.inc foo-simple.php.php-sat

Passing --print-included-files will give yet another extra file with a result:

$ php-sat -i foo-simple.php -o foo-simple.php.php-sat --simple-inclusion --print-included-files --extended-output
$ ls
foo-simple.php foo-complex.php foo.php foo.inc foo-simple.php.php-sat foo.inc.php-sat

Interpreting the output

Please take a look at the bug-patterns section to find out how the results should be interpreted.