review unknown code with static analysis - bredaphp
TRANSCRIPT
Review unknown code with static analysis
Breda, Nederlands, Dec. 2016
Agenda
Reviewing code
Static analysis for PHP
A session in which you are the hero
Review this project
We don't know what it does
We have never heard about it
We don't run it
We don't know the authors
Can we have an opinion?
How to review code
Reading code is humanly possible : its an art
Unit test are not adapted for review
Dynamic analysis is not fit for review
We need to explore code
we cannot only rely on the current state
Speaker
Damien Seguy
Exakat CTO
Den Haag : ik ben een boterham
Static analysis for PHP : SCAP
PHP doc author
Source code is structured
Source code is a structured database
All we need is tools to query it
This is static analysis
Migration PHP 7.0->7.1
Inco
mpa
tibilit
iesNe
w fe
atur
es
PHP LINT
php -l <fichier.php>
Paralell executions
jakub-onderka/php-paralell-lint
Various versions of PHP : 7.0, 7.1, 7.2, 5.6, 5.5
Checked 5982 files in 28.4 seconds Syntax error found in 4 files
------------------------------------------------------------ Parse error: /vendor2/symfony/symfony/src/Symfony/Component/Validator/Constraints/False.php:22 20| * @api 21| */ > 22| class False extends IsFalse 23| { 24| } Fatal error: Cannot use 'False' as class name as it is reserved ------------------------------------------------------------ Parse error: /vendor2/symfony/symfony/src/Symfony/Component/Validator/Constraints/Null.php:22 20| * @api 21| */ > 22| class Null extends IsNull 23| { 24| } Fatal error: Cannot use 'Null' as class name as it is reserved ------------------------------------------------------------ Parse error: /vendor2/symfony/symfony/src/Symfony/Component/Validator/Constraints/True.php:22 20| * @api 21| */ > 22| class True extends IsTrue 23| { 24| } Fatal error: Cannot use 'True' as class name as it is reserved ------------------------------------------------------------ Parse error: /vendor_user/windid_client/src/windid/service/base/WindidUtility.php:93 91| $imageInfo = @getimagesize($file); 92| $exts = array('1'=>'gif', '2'=>'jpg', '3'=>'png'); > 93| if (!isset($exts[$imageInfo[2]])) continue; 94| $ext = $exts[$imageInfo[2]]; 95| $filename = rand(1000,9999). '.'.$ext; Fatal error: 'continue' not in the 'loop' or 'switch' context
PHP LINT - 7.0/1/2
Checked 5982 files in 29.7 seconds Syntax error found in 1 file
------------------------------------------------------------ Parse error: /vendor2/mockery/mockery/tests/Mockery/MockingVariadicArgumentsTest.php:52 50| abstract class TestWithVariadicArguments 51| { > 52| public function foo(...$bar) 53| { 54| return $bar; Unexpected '.', expecting '&' or variable (T_VARIABLE)
PHP LINT - 5.5
PHP LINT - 5.6Checked 5982 files in 31 seconds No syntax error found
PHP LINT
Not compatible with PHP 7.0 +
Not compatible with PHP 5.5-
Uses Symfony
@getimagesize ? vendor2 ?
5982 files
Metrics
PHPloc, PHPmetrics, PHP MD
Provides global values about the code
Cyclomatic complexity, LOC…
PHPLOC Directories 1143 Files 5982
Size Lines of Code (LOC) 835199 Comment Lines of Code (CLOC) 252075 (30.18%) Non-Comment Lines of Code (NCLOC) 583124 (69.82%) Logical Lines of Code (LLOC) 195283 (23.38%) Classes 178062 (91.18%) Average Class Length 29 Minimum Class Length 0 Maximum Class Length 3141 Average Method Length 4 Minimum Method Length 0 Maximum Method Length 879 Functions 1477 (0.76%) Average Function Length 1 Not in classes or functions 15744 (8.06%)
Cyclomatic Complexity Average Complexity per LLOC 0.30 Average Complexity per Class 10.82 Minimum Class Complexity 1.00 Maximum Class Complexity 1177.00 Average Complexity per Method 2.65 Minimum Method Complexity 1.00 Maximum Method Complexity 387.00
[...]
PHPLOC Dependencies Global Accesses 2158 Global Constants 1738 (80.54%) Global Variables 31 (1.44%) Super-Global Variables 389 (18.03%) Attribute Accesses 50986 Non-Static 49206 (96.51%) Static 1780 (3.49%) Method Calls 113735 Non-Static 103683 (91.16%) Static 10052 (8.84%)
Structure Namespaces 851 Interfaces 693 Traits 11 Classes 5245 Abstract Classes 301 (5.74%) Concrete Classes 4944 (94.26%) Methods 39581 Scope Non-Static Methods 37468 (94.66%) Static Methods 2113 (5.34%) Visibility Public Methods 31500 (79.58%) Non-Public Methods 8081 (20.42%) Functions 1185 Named Functions 306 (25.82%) Anonymous Functions 879 (74.18%) Constants 2658 Global Constants 361 (13.58%) Class Constants 2297 (86.42%)
PHPMetrics
PHPMetrics
Automated code review
PHP code review PHP code
regex reads PHP
Extract interesting points
Works with keywords
PHP7cc, grep
php7ccFile: /vendor_user/windid_client/wind/convert/WindGeneralConverter.php > Line 33: PHP 4 constructors are now deprecated public function WindGeneralConverter($sourceLang = '', $targetLang = '', $forceTable = false) { }
File: /vendor2/symfony/symfony/src/Symfony/Component/Validator/Constraints/Null.php > Line 22: Reserved name "null" used as a class, interface or trait name class Null extends \Symfony\Component\Validator\Constraints\IsNull { }
File: /vendor_user/windid_client/wind/filter/WindHandlerInterceptorChain.php > Line 61: Function argument(s) returned by "func_get_args" might have been modified func_get_args();
File: /vendor_user/windid_client/wind/http/session/handler/WindSessionHandler.php > Line 156: Check that callbacks that are passed to "session_set_save_handler" and return false or -1 (if any) operate correctly session_set_save_handler(array($this, 'open'), array($this, 'close'), array($this, 'read'), array($this, 'write'), array($this, 'destroy'), array($this, 'gc'));
File: /vendor_user/windid_client/wind/security/WindMcryptCbc.php > Line 31: Removed function "mcrypt_cbc" called mcrypt_cbc(MCRYPT_DES, $key, $string, MCRYPT_ENCRYPT, $iv); > Line 49: Removed function "mcrypt_cbc" called mcrypt_cbc(MCRYPT_DES, $key, $string, MCRYPT_DECRYPT, $iv);
Total : 83 issues
Automated code review
Semantic read of the code
Reports interesting issues
Works with AST
PHP7mar, Phan, exakat
Automated code review
PHP 5 / 7 Calisthenics ClearPHP
Performance
AST
<?php
class Foo { function bar($arg) { return \StrToUpper($arg + 2); } }
$foo = new Foo(); $foo->bar(__FILE__);
?>
Semantics and definitions
PHP7mar : nikic/php5-ast
PHAN : ext/ast (PHP 7 only)
Exakat : AST in a graph database
SonarQube : Java-build AST
PHPstorm : internal IDE AST
Semantics and definitions
Removes spaces, comments, documentations
Removes delimiters
( ) { } [ ] " ' ` ; :
Good network to link definition with usage
PHANsrc/Org/OrgBundle/Controller/OrgController.php:12 PhanTypeMismatchArgument Argument 1 (data) is bool but \Org\OrgBundle\Controller\OrgController::createJsonResponse() takes array defined at src/Topxia/WebBundle/Controller/BaseController.php:120
Total : 13315 results1235 issues
vendor_user/windid_client/wind/mail/protocol/WindPop3.php:186 PhanUndeclaredTypeParameter Parameter of undeclared type \baoolean
276 issues
vendor_user/windid_client/wind/base/WindFactory.php:325 PhanTypeArraySuspicious Suspicious array access to bool
184 issues
vendor2/imagine/imagine/lib/Imagine/Image/AbstractLayers.php:49 PhanParamSignatureMismatch Declaration of function get($offset) should be compatible with function get(int $offset) : \Imagine\Image\ImageInterface defined in vendor2/imagine/imagine/lib/Imagine/Image/LayersInterface.php:97
src/Classroom/ClassroomBundle/Controller/ClassroomAdminController.php:84 PhanUndeclaredMethod Call to undeclared method \Classroom\ClassroomBundle\Controller \ClassroomAdminController::createErrorResponse
1919 issues
808 issues
PHAN [PhanRedefineFunction] => 31 [PhanTypeMismatchForeach] => 31 [PhanUndeclaredClassInstanceof] => 32 [PhanDeprecatedFunction] => 43 [PhanUndeclaredClassConstant] => 49 [PhanUndeclaredTypeProperty] => 60 [PhanParamSignatureMismatchInternal] => 79 [PhanUndeclaredClassCatch] => 94 [PhanParamTooMany] => 101 [PhanUndeclaredFunction] => 102 [PhanTypeMissingReturn] => 126 [PhanStaticCallToNonStatic] => 164 [PhanTypeArraySuspicious] => 184 [PhanTypeMismatchDefault] => 194 [PhanNonClassMethodCall] => 202 [PhanUndeclaredTypeParameter] => 276 [PhanUndeclaredConstant] => 417 [PhanUndeclaredVariable] => 432 [PhanTypeMismatchProperty] => 530 [PhanUndeclaredMethod] => 808 [PhanTypeMismatchArgumentInternal] => 854 [PhanUndeclaredClassMethod] => 1082 [PhanTypeMismatchReturn] => 1236 [PhanTypeMismatchArgument] => 1716 [PhanParamSignatureMismatch] => 1840 [PhanUndeclaredProperty] => 2485
53 analyses
PHANsrc/Classroom/Service/Classroom/Tests/ClassroomReviewServiceTest.php:227 PhanDeprecatedFunction Call to deprecated function \Classroom\Service\Classroom\Tests\ClassroomReviewServiceTest::setExpectedException()
defined at vendor/phpunit/phpunit/src/Framework/TestCase.php:466
43 issues
PHP 7 helps SCAP
Type hint, return type hint, scalar typehint
Phan understands PHPDOC
Dynamic code is very difficult to analyze
Flow Control diagram
Handle the way the code is executed
Based on AST, adds sequence tracking
Applied in RIPS
<?php $x = source(); if ($x < 10) { $y = $x + 1; $x = corrige($y); } else { $y = $x; }
Flow Control Graph
$x = source();
if ($x < 10)
$y = $x + 1;
$x = corrige($y);
$y = $x;
PHP
Exit
ElseThen
<?php $x = source(); if ($x < 10) { $y = $x + 1; $x = corrige($y); } else { $y = $x; }
Program Dependency Graph
$x = source();
if ($x < 10)
$y = $x + 1;
$x = corrige($y);
$y = $x;Depend de $x
Depend de $x
Depend de $y
Depend de $x
Depend de $x
Depend de $x
<?php $x = source(); if ($x < 10) { $y = $x + 1; $x = corrige($y); } else { $y = $x; }
What about PHP?
Most of those analysis focus on informatics concepts
Some analysis focus on PHP's specifics
Common practices
Special PHP gotchas
Exakat analysisfunction __destruct() { throw …} : 0,5%
function foo($a, $a, $a) {} : 0,5%
!!(expression) : 7.4%
substr($a, 2, 4) == 'abc' : 9 %
$a ? $b ? $c : $d : $e ; 10%
foreach($a as &$b) {} : 21%
if (strpos($a, $b)) {} : 51 %
include('file.php') : 52%
Clean code for PHP
Best practices
in-house, PSR, calisthenics, other inspirations
Code mantras, code kata
PHP Manual
Migration guides
PHP
List of used PHP features
PHP
List of directives
Project preferences
List of directives
What does this app do?
Welcome to the inventories
List of literal in the code
Integers, real, arrays, strings
Names for classes, methods, traits, variables, interfaces…
Error
String used with exit, die and new Exception()
Variables
$orderBy 685 $token 690 $response 721 $paginator 752 $temp 828 $params 891 $value 925 $type 955 $thread 968 $order 982 $member 1042 $classroom 1115 $limit 1222 $start 1320 $currentUser 1334 $userId 1352 $file 1391 $data 1408 $i 1494 $lesson 1504 $sql 1528 $courseId 1626 $key 1716 $fields 2214 $result 2600 $course 2742 $request 3219 $id 3529 $conditions 3870 $user 4505
Also : 271 used-once variables
ClassesOrderServiceTest 2 FileController 2 ClassroomDataTag 2 LiveCourseController 2 UploadFileController 2 NoteController 2 BlockController 2 OrderLogDaoImpl 2 OpenCourseController 2 FileFilter 2 CourseOrderController 2 Member 2 CoinController 2 ThreadServiceTest 3 BaseProcessor 3 MobileController 3 UserController 3 CategoryDaoImpl 3 CourseReviewController 3 TeacherController 3 AlipaySubmit 3 ThreadServiceImpl 3 ThreadPostDaoImpl 3 AlipayNotify 3 ThreadDaoImpl 3 CourseController 5 DefaultController 5 DefaultControllerTest 5 Configuration 6
Comparisons
none 9 vip 10 .. 10 yes 10 material 11 coin 11 created 11 teacher 12 closed 12 error 13 1 14 RMB 15 0 16 paid 16 lesson 18 liveOpen 19 trend 19 cloud 19 ok 20 Coin 21 classroom 22 video 25 self 25 testpaper 27 success 32 live 32 course 39 published 43 _empty_ 71 POST 237
Strings used in comparisons $a == 'ok'
Occurrences counts
Going further
Deptrac
Check that classes stay within their layer
Manual configuration
Until frameworks define layers
Going even furtherDynamic code
40% of the code is actually constant
Transpilage : https://github.com/jaytaph/Transphpile
PHP inspections : Integrated in phpStorm
sensio labs insight : Static analysis for Symfony
Integrate static analysis in IC
Liste des SCAP citésDeptrac
Exakat
PHP7mar
Phan
PHP Inspections
Phploc
PHPMD
PHP 7 cc
PHPmetrics
RIPS
Transphpile
Edusoho