Post on 08-Jan-2017
Static Analysis of PHP
Code
How the Heck did I write so many Bugs?
International PHP Conference Berlin, June 2016
By Rouven Weßling ( ) Ecosystem Developer / Developer Evangelist, Contentful
@RouvenWesslingphoto credit: by Achim Fischer Brandenburg Gate Berlin (license)
What is StaticAnalysis?
Analysing software withoutexecuting it.
Dynamic Analysisxdebug
xhprof
PHP Analyzer
PHP Vulnerability Hunter
Assertions
Why use StaticAnalysis?
Spend less time on unit tests...
...and code review
class ClientTest extends \PHPUnit_Framework_TestCase { public function testGetSynchronizationManager() { $client = new Client('b4c0n73n7fu1', 'cfexampleapi');
$this->assertInstanceOf(Manager::class, $client->getSynchronizationManager()); } }
Easy to integrate in ContinuousIntegration
Find issues that can not be foundthrough unit tests
PHP 7
Abstract Syntax TreeScalar TypesStrict Types
PHP is dynamic �ReflectionVariable variablesReferencing classes/functions/properties by string
The more static your code is, theeasier it's to reason about.
Some tools
phpmd phan phpcs phpunit phploc phpcpd phpsa php7cc
Coupling Detector Mondrian PHP
Assumption PhpCodeAnalyzer PHPCodeFixer php7mar PHP
Semantic Versioning Checker PHP Inspection PHP
lint PHP Depend PhpMetrics PHPCheckstyle PHP
Reaper PHP vuln hunter RIPS Parse SonarQube Side
Channel
Analyzer TaintPHP Deptrac PhpDependencyAnalysis PHP
semver checker
phpmd phan phpcs phpunit phploc phpcpd phpsa php7cc
Coupling Detector Mondrian PHP
Assumption PhpCodeAnalyzer PHPCodeFixer php7mar PHP
Semantic Versioning Checker PHP Inspection PHP
lint PHP Depend PhpMetrics PHPCheckstyle PHP
Reaper PHP vuln hunter RIPS Parse SonarQube Side
Channel
Analyzer TaintPHP Deptrac PhpDependencyAnalysis PHP
semver checker
phpmd phan phpcs phpunit phploc phpcpd phpsa php7cc
Coupling Detector Mondrian PHP
Assumption PhpCodeAnalyzer PHPCodeFixer php7mar PHP
Semantic Versioning Checker PHP Inspection PHP
lint PHP Depend PhpMetrics PHPCheckstyle PHP
Reaper PHP vuln hunter RIPS Parse SonarQube Side
Channel
Analyzer TaintPHP Deptrac PhpDependencyAnalysis PHP
semver checker
phpmd phan phpcs phpunit phploc phpcpd phpsa php7cc
Coupling Detector Mondrian PHP
Assumption PhpCodeAnalyzer PHPCodeFixer php7mar PHP
Semantic Versioning Checker PHP Inspection PHP
lint PHP Depend PhpMetrics PHPCheckstyle PHP
Reaper PHP vuln hunter RIPS Parse SonarQube Side
Channel
Analyzer TaintPHP Deptrac PhpDependencyAnalysis PHP
semver checker
phpmd phan phpcs phpunit phploc phpcpd phpsa php7cc
Coupling Detector Mondrian PHP
Assumption PhpCodeAnalyzer PHPCodeFixer php7mar PHP
Semantic Versioning Checker PHP Inspection PHP
lint PHP Depend PhpMetrics PHPCheckstyle PHP
Reaper PHP vuln hunter RIPS Parse SonarQube Side
Channel
Analyzer TaintPHP Deptrac PhpDependencyAnalysis PHP
semver checker
phpmd phan phpcs phpunit phploc phpcpd phpsa php7cc
Coupling Detector Mondrian PHP
Assumption PhpCodeAnalyzer PHPCodeFixer php7mar PHP
Semantic Versioning Checker PHP Inspection PHP
lint PHP Depend PhpMetrics PHPCheckstyle PHP
Reaper PHP vuln hunter Parse SonarQube Side
Channel
Analyzer TaintPHP Deptrac PhpDependencyAnalysis PHP
semver checker
phpmd phan phpcs phpunit phploc phpcpd phpsa php7cc
Coupling Detector Mondrian PHP
Assumption PhpCodeAnalyzer PHPCodeFixer php7mar PHP
Semantic Versioning Checker PHP Inspection PHP
lint PHP Depend PhpMetrics PHPCheckstyle PHP
Reaper PHP vuln hunter Parse SonarQube Side
Channel
Analyzer TaintPHP Deptrac PhpDependencyAnalysis PHP
semver checker
phpmd phan phpcs phpunit phploc phpcpd phpsa PHP
Coupling Detector Mondrian PHP
Assumption PhpCodeAnalyzer PHPCodeFixer php7mar PHP
Semantic Versioning Checker PHP Inspection PHP
lint PHP Depend PhpMetrics PHPCheckstyle PHP
Reaper PHP vuln hunter Parse SonarQube Side
Channel
Analyzer TaintPHP Deptrac PhpDependencyAnalysis PHP
semver checker
PHP lint
php -l
Compiles PHP script with the actual PHP compiler
It's already installed on your computer
Can be used to test compatibility with multiple PHP
versions
<?php
namespace Contentful\Log
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
class NullLogger implements LoggerInterface
{
public function getTimer()
{
return new NullTimer;
}
public function log($api, RequestInterface $request, StandardTimer $timer, ResponseInterface $response = null, \Exception $exception = null)
{
}
}
PHP 7.0.3 | 10 parallel jobs
.................................X...... 40/40 (100 %)
Checked 40 files in 0.5 seconds
Syntax error found in 1 file
------------------------------------------------------------
Parse error: src/Log/NullLogger.php:9
7| namespace Contentful\Log
8|
> 9| use Psr\Http\Message\RequestInterface;
10| use Psr\Http\Message\ResponseInterface;
11|
Unexpected 'use' (T_USE), expecting '{'
Make your life easierUse PHP-Parallel-Lint
Deptrac
Software has layersThere should be rules about those layersRules are easily broken
1. Define the layers of your architecture2. Define what layers another layer can access3. Profit!!!
layers: - name: Controller collectors: - type: className regex: .*Controller.* - name: Entity collectors: - type: className regex: AstaRwth\\VorkursticketBundle\\Entity\\.*
ruleset: Controller: - Service - Entity - Form Service: - Repository Command: - Entity Entity: - Validator
How it works
Parses all files in your codeStores which classes access which others classesChecks the graph for rule violations
deptrac is alpha, not production ready.
please help us and report feedback / bugs.
Start to create an AstMap for 24 Files.
........................
AstMap created.
start emitting dependencies "InheritanceDependencyEmitter"
start emitting dependencies "BasicDependencyEmitter"
end emitting dependencies
start flatten dependencies
end flatten dependencies
collecting violations.
formatting dependencies.
[...]\Services\PdfOrder::5 must not depend on [...]\Entity\Vorkursticket (Service on Entity)
[...]\Services\PdfOrder::23 must not depend on [...]\Entity\Vorkursticket (Service on Entity)
Found 2 Violations
phan
Type safety for PHP
Checks docblocks
Signature mismatches
Unused code
How it works
Makes 2 passes over the codebase1. Build a list of all classes, functions, methods, etc.2. Go trough each function and follow the type ofeach variable
/** * @param Locale|string|null $locale * * @return string */ public function getDescription($locale = null) { $localeCode = $this->getLocaleFromInput($locale);
// This checks happens after the call to getLocaleFromInput to make sure // the Exception for invalid locales is still thrown. if ($this->description === null) { return null; }
return $this->description->$localeCode; }
src/Delivery/Asset.php:74 PhanTypeMismatchReturn Returning type null but getDescription() is declared to return string
class ContentType { /** * The fields, keyed by ID. * * @var object */ private $fields = []; }
src/Delivery/ContentType.php:34 PhanTypeMismatchProperty Assigning array to property but \contentful\delivery\contenttype::fields is object
public function __call($name, $arguments) { // Lots of code here
if ($result instanceof Link) { return $client->resolveLink($result); }
return array_map(function ($value) use ($client) { if ($value instanceof Link) { return $client->resolveLink($value); }
return $value; }, $result); }
src/Delivery/DynamicEntry.php:126 PhanTypeMismatchArgumentInternal Argument 2 (input1) is \contentful\delivery\link but \array_map() takes array
Not a bug
Not a bug
Don't trust blindly
Bad news?Requires php-astNot easy to deal with library codeNoisy - not easily integrated in CI.
The future
phan is using brute force for type checkingRoughly as good as the compiler for a staticallytyped languageWorks, but a Control Flow Graph could give evendeeper insight
int foo(int length) { int x = 0; for (int i = 0; i < length; i++) x += 1
return length/x; }
Bottom lineThere are dozens of tools - pick what's necessary foryouMake them part of your Continuous Integration setupNever trust. Make sure you understand where theerror is coming from.
Slides available on Slideshare:http://www.slideshare.net/rwessling/static-analysis-of-
php-code-ipc-berlin-2016