PHP Static Code Review

25
PHP Static Code Review München, Deutschland, October 27th

description

Even nowadays, PHP code is mostly manually audited. Expert pore over actual code, in search for bugs or code smells. Actually, it is possible to have PHP do this work itself ! Strengthened with the internal Tokenizer, bolstered by the manual, it is able to scan thousands of lines of code, without getting bored, and bringing pragmatic pieces of wisdom: official manual recommendations, version migration, code pruning and security. In the end, it deliver a global overview of the code, without reading it.

Transcript of PHP Static Code Review

Page 1: PHP Static Code Review

PHP Static Code Review

München, Deutschland, October 27th

Page 2: PHP Static Code Review

Definition

• A kind of code analysis where the code is reviewed without running it.

• Just like we would do ourselves!

• Where can it help

Page 3: PHP Static Code Review

Who is speaking?

• Damien Seguy

• CTO at exakat

• Phather of the plush toy elePHPant

• Working on automated code audit

Page 4: PHP Static Code Review
Page 5: PHP Static Code Review

PHP tokenizer

<?php function x($a) {        return $a;}x(1, 2);?>

[0] => Array ( [0] => 372 [1] => <?php

[2] => 1 )

[1] => Array ( [0] => 334 [1] => function [2] => 2 )

[2] => Array ( [0] => 375 [1] => [2] => 2 )

[3] => Array ( [0] => 307 [1] => x [2] => 2 )

function token

whitespace token

T_STRING

Total : 30 tokens

Page 6: PHP Static Code Review

Internals

Code

Analyze Report

AST

Page 7: PHP Static Code Review
Page 8: PHP Static Code Review

<?php function x($a) {        return $a;}x(1, 2);?>

Page 9: PHP Static Code Review

Found• Dead code

• Undefined structures

• Unused structures

• Illogical exp.

• Slow code

• Bad practices

• Unsafe code

• Maintainability

• Bug issue

• Ancient style

• Uninitialized vars

• Taint propagation

Page 10: PHP Static Code Review

<?phpswitch ($this->consume()){     case "\x09":    case "\x0A":    case "\x0B":    case "\x0B":    case "\x0C":    case "\x20":    case "\x3C":    case "\x26":    case false:        break;    case "\x23":        switch ($this->consume())        {            case "\x78":            case "\x58":                $range = '0123456789ABCDEFabcdef';                return $a++;                break;        }    }?>

Page 11: PHP Static Code Review

<?php

class x extends y {    function array_single_quote($array) {       return parent::array_map("single_quote", $array);   } }

/* Calling each other */ function debug_dump_backtrace($msg='Calling BackTrace',$die=false) { debug_sysmsg($msg); error($msg,'note',null,$die,true); }

/* Defined in another file */ function debug_sysmsg($msg) {     system_message(array(‘title'=>_('Debug'),'body'=>$msg,'type'=>'debug'));       debug_dump_backtrace($msg, true); }

?>

Page 12: PHP Static Code Review

    protected function openString($end, &$out=null, $nestingOpen, $rejectStrs = null) {         $nestingLevel = $count = 0;        $content = array();        while ($this->match($patt, $m, false)) {             $tok = $m[2];            if ($tok == "@{" && $this->interpolation($inter)) {                 $content[] = $inter;                continue;            }            if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {                 $ount = null;                break;            }            $content[] = $tok;            $count += strlen($tok);        }        $this->eatWhiteDefault = $oldWhite;        if (count($content) == 0) return false;        $out = array("string", "", $content);        return true;    }

Page 13: PHP Static Code Review

Spot bugs early

Code Test PreProd Production

Run it at commit Run it as audit

Page 14: PHP Static Code Review

When does it help

• Audit external libraries

• Help port to a new system

• Search for weak code fragments

• Hint at refactoring

Page 15: PHP Static Code Review

Report

• Bugs

• Useless code

• Suggestions

Page 16: PHP Static Code Review

Bugs

<?php 

if($content = file_get_contents($file)) {   $content = trim($content);           $content = substr($content, -2) == ‘>’ ? substr($content, 0, -2) : $content;}?> 

Page 17: PHP Static Code Review

Useless code

<?php

// inside a legit class $this->module->xmlRequest;$_G['setting']['debug'];

if (!empty($a) && in_array($tokens, $a)) {        false;}

?>

Page 18: PHP Static Code Review

Suggestions<?php // Nested ternary should be turned into if then structures     $operation == 'ENCODE' ? sprintf('%010d', $expiry ? $expiry + time( ) : 0) . substr(md5($string . $egiskeys), 0, 16) . $string : base64_decode(substr($string, $key_length))    // Multiply by one is useless     SetCache($prefix, $key, $row, 60*60*1);

$xtime *= 1;

// Backward compatible syntax     $bits = split('.', $string);    $y = $bits[0];     

// Available syntax with recent PHP versions     $y = split('.', $string)[0];?>

Page 19: PHP Static Code Review

Where it doesn’t help

• Unit tests

• Architecture

• Old traditions that won’t change

• Semantic errors

Page 20: PHP Static Code Review

Architecture

• No framework context

• Conception is done before coding

• Of course!

• Static audit will report standards, not norms

Page 21: PHP Static Code Review

Old traditions<?php   $pna = explode(')(', $pn);   while (list($k, $v) = each($pna)) {        $lst = explode('"', $v);       if (isset($lst[3])) {            $pn[$lst[1]] = $lst[3];       } else {           $pn[$lst[1]] = '';       }   }?>

10 % of nowadays applications uses this instead of foreach()

Page 22: PHP Static Code Review

Old traditions

<?php    defined('WEB_ROOT') || define('WEB_ROOT', dirname(__FILE_));

// also classic usage fopen($pFilename, 'w') or die("can't open file"); 

?>

Page 23: PHP Static Code Review

Semantic errors<?php    $babycarriage = new carriage();    $wheel1 = new Racingwheel();    $wheel2 = new Racingwheel();    $wheel3 = new Racingwheel();    $wheel4 = new Rhinoceros();        $babycarriage->installWheels($wheel1, 

$wheel2, $wheel3, $wheel4);

    ?>

Undefined classes : Vehicle, Racingwheel, Rhinoceros

Page 24: PHP Static Code Review

Available analyzers• PHP code sniffer

• PHP MD

• Scrutinizer-ci

• Fortify

• insight from Sensio

• Exakat