public function analyze() { $atoms = array('Property', 'Staticproperty'); $this->atomIs($atoms)->hasIn(array('PREPLUSPLUS', 'POSTPLUSPLUS', 'DEFINE', 'CAST'))->back('first'); $this->prepareQuery(); $this->atomIs($atoms)->inIs(array('LEFT', 'APPEND'))->atomIs(array('Assignation', 'Arrayappend'))->back('first'); $this->prepareQuery(); // arguments : reference variable in a custom function $this->atomIs($atoms)->savePropertyAs('rank', 'rank')->inIs('ARGUMENT')->inIs('ARGUMENTS')->hasNoIn('METHOD')->tokenIs(array('T_STRING', 'T_NS_SEPARATOR'))->functionDefinition()->outIs('ARGUMENTS')->outIs('ARGUMENT')->samePropertyAs('rank', 'rank', true)->is('reference', true)->back('first'); $this->prepareQuery(); // PHP functions that are references $data = new Methods(); $functions = $data->getFunctionsReferenceArgs(); $references = array(); foreach ($functions as $function) { if (!isset($references[$function['position']])) { $references[$function['position']] = array('\\' . $function['function']); } else { $references[$function['position']][] = '\\' . $function['function']; } } foreach ($references as $position => $functions) { $this->atomIs($atoms)->inIsIE('VARIABLE')->is('rank', $position)->inIs('ARGUMENT')->inIs('ARGUMENTS')->hasNoIn('METHOD')->atomIs('Functioncall')->tokenIs(array('T_STRING', 'T_NS_SEPARATOR', 'T_UNSET'))->fullnspathIs($functions)->back('first'); $this->prepareQuery(); } // Class constructors (__construct) $this->atomIs($atoms)->savePropertyAs('rank', 'rank')->inIs('ARGUMENT')->inIs('ARGUMENTS')->hasNoIn('METHOD')->tokenIs(array('T_STRING', 'T_NS_SEPARATOR'))->atomIs('Functioncall')->hasIn('NEW')->classDefinition()->outIs('BLOCK')->outIs('ELEMENT')->analyzerIs('Classes/Constructor')->outIs('ARGUMENTS')->outIs('ARGUMENT')->samePropertyAs('rank', 'rank')->is('reference', true)->back('first'); $this->prepareQuery(); }
public function analyze() { $methods = new Methods(); $nonDeterminist = $methods->getNonDeterministFunctions(); $nonDeterminist = "'\\\\" . implode("', '\\\\", $nonDeterminist) . "'"; $whereNonDeterminist = 'where( __.repeat( __.out() ).emit( hasLabel("Functioncall") ).times(' . self::MAX_LOOPING . ').hasLabel("Functioncall").where(__.in("METHOD", "NEW").count().is(eq(0))).has("token", within("T_STRING", "T_NS_SEPARATOR")).filter{ it.get().value("fullnspath") in [' . $nonDeterminist . ']}.count().is(eq(0)) )'; // foreach with only one value $this->atomIs('Foreach')->outIs('VALUE')->atomIs('Variable')->savePropertyAs('code', 'blind')->back('first')->outIs('BLOCK')->raw('where( __.repeat( __.out() ).emit( hasLabel("Variable") ).times(' . self::MAX_LOOPING . ').filter{ it.get().value("fullcode") == blind}.count().is(eq(0)) )')->raw($whereNonDeterminist)->back('first'); $this->prepareQuery(); // foreach with key value $this->atomIs('Foreach')->outIs('VALUE')->atomIs('Keyvalue')->outIs('KEY')->savePropertyAs('fullcode', 'k')->inIs('KEY')->outIs('VALUE')->savePropertyAs('code', 'v')->inIs('VALUE')->back('first')->outIs('BLOCK')->raw('where( __.repeat( __.out() ).emit( hasLabel("Variable") ).times(' . self::MAX_LOOPING . ').filter{ it.get().value("fullcode") in [v, k]}.count().is(eq(0)) )')->raw($whereNonDeterminist)->back('first'); $this->prepareQuery(); // foreach with complex structures (property, static property, arrays, references... ?) // for $this->atomIs('For')->outIs('INCREMENT')->atomIs('Void')->back('first'); $this->prepareQuery(); $this->atomIs('For')->raw('where( __.sideEffect{ blind = []}.out("INCREMENT", "INIT").repeat( out() ).emit( hasLabel("Variable")).times(' . self::MAX_LOOPING . ').sideEffect{ blind.push(it.get().value("code")); }.fold() )')->outIs('BLOCK')->raw('where( __.repeat( __.out() ).emit( hasLabel("Variable") ).times(' . self::MAX_LOOPING . ').filter{ it.get().value("fullcode") in blind}.count().is(eq(0)) )')->raw($whereNonDeterminist)->back('first'); $this->prepareQuery(); // for with complex structures (property, static property, arrays, references... ?) // do...while $this->atomIs('Dowhile')->raw('where( __.sideEffect{ blind = []}.out("CONDITION").repeat( out() ).emit( hasLabel("Variable")).times(' . self::MAX_LOOPING . ').sideEffect{ blind.push(it.get().value("code")); }.fold() )')->outIs('BLOCK')->raw('where( __.repeat( __.out() ).emit( hasLabel("Variable") ).times(' . self::MAX_LOOPING . ').filter{ it.get().value("fullcode") in blind}.count().is(eq(0)) )')->raw($whereNonDeterminist)->back('first'); $this->prepareQuery(); // do while with complex structures (property, static property, arrays, references... ?) // while $this->atomIs('While')->raw('where( __.sideEffect{ blind = []}.out("CONDITION").repeat( out() ).emit( hasLabel("Variable")).times(' . self::MAX_LOOPING . ').sideEffect{ blind.push(it.get().value("code")); }.fold() )')->outIs('BLOCK')->raw('where( __.repeat( __.out() ).emit( hasLabel("Variable") ).times(' . self::MAX_LOOPING . ').filter{ it.get().value("fullcode") in blind}.count().is(eq(0)) )')->raw($whereNonDeterminist)->back('first'); $this->prepareQuery(); // while with complex structures (property, static property, arrays, references... ?) }
public function analyze() { // this is for functions defined within PHP $data = new Methods(); $functions = $data->getFunctionsArgsInterval(); $argsMins = array(); $argsMaxs = array(); foreach ($functions as $function) { if ($function['args_min'] > 0) { $argsMins[$function['args_min']][] = '\\' . $function['name']; } if ($function['args_max'] < 100) { $argsMaxs[$function['args_max']][] = '\\' . $function['name']; } } foreach ($argsMins as $nb => $f) { $this->atomFunctionIs($f)->outIs('ARGUMENTS')->isLess('count', $nb)->back('first'); $this->prepareQuery(); } foreach ($argsMaxs as $nb => $f) { $this->atomFunctionIs($f)->outIs('ARGUMENTS')->isMore('count', $nb)->back('first'); $this->prepareQuery(); } // this is for custom functions $this->atomIs('Functioncall')->hasNoIn('METHOD')->tokenIs(array('T_STRING', 'T_NS_SEPARATOR'))->outIs('ARGUMENTS')->savePropertyAs('count', 'args_count')->inIs('ARGUMENTS')->functionDefinition()->analyzerIsNot('Functions/VariableArguments')->outIs('ARGUMENTS')->isMore('args_min', 'args_count')->back('first'); $this->prepareQuery(); $this->atomIs('Functioncall')->hasNoIn('METHOD')->tokenIs(array('T_STRING', 'T_NS_SEPARATOR'))->outIs('ARGUMENTS')->savePropertyAs('count', 'args_count')->inIs('ARGUMENTS')->functionDefinition()->analyzerIsNot('Functions/VariableArguments')->outIs('ARGUMENTS')->isLess('args_max', 'args_count')->back('first'); $this->prepareQuery(); }
public function analyze() { $this->atomIs('Variable')->hasIn(array('NOT', 'AT', 'OBJECT', 'NEW', 'RETURN', 'CONCAT', 'SOURCE', 'CODE', 'INDEX', 'CONDITION', 'THEN', 'ELSE', 'KEY', 'VALUE', 'NAME', 'DEFINE', 'PROPERTY', 'METHOD', 'VARIABLE', 'SIGN', 'THROW', 'CAST', 'CASE', 'CLONE', 'FINAL', 'CLASS', 'GLOBAL', 'PPP')); $this->prepareQuery(); // Reading inside an assignation $this->atomIs('Variable')->inIs('LEFT')->atomIs('Assignation')->codeIs('=')->hasIn(array('NOT', 'AT', 'OBJECT', 'NEW', 'RETURN', 'CONCAT', 'SOURCE', 'CODE', 'INDEX', 'CONDITION', 'THEN', 'ELSE', 'KEY', 'VALUE', 'NAME', 'DEFINE', 'PROPERTY', 'METHOD', 'VARIABLE', 'SIGN', 'THROW', 'CAST', 'CASE', 'CLONE', 'FINAL', 'CLASS', 'PPP'))->back('first'); // note : NAME is for Switch!! $this->prepareQuery(); // $this is always read $this->atomIs('Variable')->codeIs('$this'); $this->prepareQuery(); // right or left, same $this->atomIs('Variable')->inIs(array('RIGHT', 'LEFT'))->atomIs(array('Addition', 'Multiplication', 'Logical', 'Comparison', 'Bitshift'))->back('first'); $this->prepareQuery(); // right only $this->atomIs('Variable')->inIs('RIGHT')->atomIs('Assignation')->back('first'); $this->prepareQuery(); // $x++ + 2 (a plusplus within another $this->atomIs('Variable')->inIs(array('PREPLUSPLUS', 'POSTPLUSPLUS'))->inIs(array('RIGHT', 'LEFT'))->atomIs(array('Addition', 'Multiplication', 'Logical', 'Comparison', 'Bitshift', 'Assignation'))->back('first'); $this->prepareQuery(); // $x++ + 2 (a plusplus in a functioncall $this->atomIs('Variable')->inIs(array('PREPLUSPLUS', 'POSTPLUSPLUS'))->hasIn('ARGUMENT')->back('first'); $this->prepareQuery(); // variable in a sequence (also useless...) $this->atomIs('Variable')->inIs('ELEMENT')->atomIs('Sequence')->back('first'); $this->prepareQuery(); // array only $this->atomIs('Variable')->inIs('VARIABLE')->atomIs(array('Array', 'Arrayappend'))->back('first'); $this->prepareQuery(); // arguments $this->atomIs('Function')->outIs('ARGUMENTS')->outIs('ARGUMENT')->atomIs('VARIABLE'); $this->prepareQuery(); // arguments : instanceof $this->atomIs('Instanceof')->outIs('LEFT')->atomIs('VARIABLE')->back('first'); $this->prepareQuery(); // arguments : normal variable in a custom function $this->atomIs('Variable')->savePropertyAs('rank', 'rank')->inIs('ARGUMENT')->inIs('ARGUMENTS')->hasNoIn('METHOD')->functionDefinition()->inIs('NAME')->outIs('ARGUMENTS')->outIs('ARGUMENT')->samePropertyAs('rank', 'rank', true)->isNot('reference', true)->back('first'); $this->prepareQuery(); // PHP functions that are passed by value $data = new Methods(); $functions = $data->getFunctionsValueArgs(); $references = array(); foreach ($functions as $function) { if (!isset($references[$function['position']])) { $references[$function['position']] = array('\\' . $function['function']); } else { $references[$function['position']][] = '\\' . $function['function']; } } foreach ($references as $position => $functions) { $this->atomIs('Variable')->is('rank', $position)->inIs('ARGUMENT')->inIs('ARGUMENTS')->atomIs('Functioncall')->hasNoIn('METHOD')->tokenIs(array('T_STRING', 'T_NS_SEPARATOR'))->fullnspathIs($functions)->back('first'); $this->prepareQuery(); } // Variable that are not a reference in a functioncall $this->atomIs('Variable')->hasIn('ARGUMENT')->hasNoParent('Function', array('ARGUMENT', 'ARGUMENTS')); $this->prepareQuery(); }
public function dependsOn() { $data = new Methods(); $this->bugfixes = $data->getBugFixes(); $depends = array(); foreach ($this->bugfixes as $bugfix) { if (!empty($bugfix['analyzer'])) { $depends[] = $bugfix['analyzer']; } } return $depends; }
public function analyze() { $dynamicAtoms = array('Variable', 'Property', 'Magicconstant', 'Staticmethodcall', 'Staticproperty'); //'Functioncall' : if they also have only constants. //'Identifier', $methods = new Methods(); $functionList = $methods->getDeterministFunctions(); $functionList = $this->makeFullNSPath($functionList); $this->atomIs(array('Addition', 'Multiplication', 'Concatenation', 'Power', 'Bitshift', 'Logical', 'Not'))->raw('where( __.repeat( out() ).emit( hasLabel("Functioncall") ).times(' . self::MAX_LOOPING . ').hasLabel("Functioncall").filter{ !(it.get().value("fullnspath") in [' . str_replace('\\', '\\\\', $this->SorA($functionList)) . ']) }.count().is(eq(0)) )')->noAtomInside($dynamicAtoms); $this->prepareQuery(); $this->atomFunctionIs(array('\\join', '\\explode', '\\implode', '\\split'))->noAtomInside($dynamicAtoms)->back('first'); $this->prepareQuery(); }
public function analyze() { $atoms = array('Property', 'Staticproperty'); $this->atomIs($atoms)->hasIn(array('NOT', 'AT', 'OBJECT', 'NEW', 'RETURN', 'CONCAT', 'SOURCE', 'CODE', 'INDEX', 'CONDITION', 'THEN', 'ELSE', 'KEY', 'VALUE', 'NAME', 'DEFINE', 'PROPERTY', 'METHOD', 'VARIABLE', 'SIGN', 'THROW', 'CAST', 'CASE', 'CLONE', 'FINAL', 'CLASS', 'GLOBAL')); // note : NAME is for Switch!! $this->prepareQuery(); // right or left, same $this->atomIs($atoms)->inIs(array('RIGHT', 'LEFT'))->atomIs(array('Addition', 'Multiplication', 'Logical', 'Comparison', 'Bitshift'))->back('first'); $this->prepareQuery(); // right only $this->atomIs($atoms)->inIs('RIGHT')->atomIs('Assignation')->back('first'); $this->prepareQuery(); // $x++ + 2 (a plusplus within another $this->atomIs($atoms)->inIs(array('PREPLUSPLUS', 'POSTPLUSPLUS'))->inIs(array('RIGHT', 'LEFT'))->atomIs(array('Addition', 'Multiplication', 'Logical', 'Comparison', 'Bitshift', 'Assignation'))->back('first'); $this->prepareQuery(); // $x++ + 2 (a plusplus in a functioncall $this->atomIs($atoms)->inIs(array('PREPLUSPLUS', 'POSTPLUSPLUS'))->hasIn('ARGUMENT')->back('first'); $this->prepareQuery(); // variable in a sequence (also useless...) $this->atomIs($atoms)->inIs('ELEMENT')->atomIs('Sequence')->back('first'); $this->prepareQuery(); // array only $this->atomIs($atoms)->inIs('VARIABLE')->atomIs(array('Array', 'Arrayappend'))->back('first'); $this->prepareQuery(); // PHP functions that are passed by value $data = new Methods(); $functions = $data->getFunctionsValueArgs(); $references = array(); foreach ($functions as $function) { if (!isset($references[$function['position']])) { $references[$function['position']] = array('\\' . $function['function']); } else { $references[$function['position']][] = '\\' . $function['function']; } } foreach ($references as $position => $functions) { $this->atomFunctionIs($functions)->outIs('ARGUMENTS')->outWithRank('ARGUMENT', $position)->atomIs($atoms); $this->prepareQuery(); } // Variable that are not a reference in a functioncall $this->atomIs($atoms)->hasIn('ARGUMENT')->raw('where( __.in("ARGUMENT").in("ARGUMENTS").hasLabel("Function").count().is(eq(0)) )')->analyzerIsNot('Variables/IsRead'); $this->prepareQuery(); // Class constructors (__construct) // Those are done in the functioncall test // Class constructors with self $this->atomIs($atoms)->savePropertyAs('rank', 'rank')->inIs('ARGUMENT')->inIs('ARGUMENTS')->atomIs('Functioncall')->codeIs('self')->hasIn('NEW')->classDefinition()->outIs('BLOCK')->outIs('ELEMENT')->_as('method')->outIs('NAME')->analyzerIs('Classes/Constructor')->back('method')->outIs('ARGUMENTS')->outIs('ARGUMENT')->samePropertyAs('rank', 'rank', true)->isNot('reference', true)->back('first'); $this->prepareQuery(); // Class constructors with self $this->atomIs($atoms)->savePropertyAs('rank', 'rank')->inIs('ARGUMENT')->inIs('ARGUMENTS')->atomIs('Functioncall')->codeIs('self')->hasIn('NEW')->classDefinition()->outIs('BLOCK')->outIs('ELEMENT')->_as('method')->outIs('NAME')->analyzerIs('Classes/Constructor')->back('method')->outIs('ARGUMENTS')->outIs('ARGUMENT')->samePropertyAs('rank', 'rank', true)->isNot('reference', true)->back('first'); $this->prepareQuery(); }
public function analyze() { // Function returning a type, then casted to that type $casts = array('T_STRING_CAST' => 'string', 'T_BOOL_CAST' => 'bool', 'T_INT_CAST' => 'int', 'T_ARRAY_CAST' => 'array', 'T_DOUBLE_CAST' => 'real'); $data = new Methods(); $returnTypes = $data->getFunctionsByReturn(); foreach ($casts as $token => $type) { $this->atomIs('Cast')->tokenIs($token)->outIs('CAST')->outIsIE('CODE')->atomIs('Functioncall')->fullnspathIs($returnTypes[$type])->back('first'); $this->prepareQuery(); } // (bool) ($a > 2) $this->atomIs('Cast')->tokenIs('T_BOOL_CAST')->outIs('CAST')->outIsIE('CODE')->atomIs('Comparison')->back('first'); $this->prepareQuery(); }
public function analyze() { $data = new Methods(); $args = $data->getInternalParameterType(); $typeConversion = array('string' => array('Magicconstant', 'Heredoc', 'String'), 'real' => 'Real', 'int' => 'Integer', 'numeric' => array('Real', 'Integer'), 'resource' => '', 'bool' => 'Boolean', 'array' => '', 'void' => 'Void', 'mixed' => ''); foreach ($args as $position => $types) { foreach ($types as $type => $functions) { if (strpos($type, ',') !== false) { continue; // No support for multiple type yet } if (!isset($typeConversion[$type]) || empty($typeConversion[$type])) { continue; } $this->atomIs('Functioncall')->analyzerIs('Functions/IsExtFunction')->fullnspathIs($functions)->outIs('ARGUMENTS')->outIs('ARGUMENT')->is('rank', $position)->isLiteral()->atomIsNot($typeConversion[$type])->back('first'); $this->prepareQuery(); } } }
public function analyze() { $data = new Methods(); $functions = $data->getFunctionsArgsInterval(); $positions = array(); foreach ($functions as $function) { if ($function['args_min'] == $function['args_max']) { continue; } if ($function['args_max'] == 100) { continue; } // Only test if the last is missing. This is sufficient $positions[$function['args_max'] - 1][] = '\\' . $function['name']; } foreach ($positions as $position => $f) { $this->atomFunctionIs($f)->outIs('ARGUMENTS')->noChildWithRank('ARGUMENT', $position)->back('first'); $this->prepareQuery(); } }
public function analyze() { // $a[3]++; $this->atomIs('Array')->hasIn(array('PREPLUSPLUS', 'POSTPLUSPLUS', 'DEFINE', 'CAST'))->back('first'); $this->prepareQuery(); // $a[1] = 2; $this->atomIs('Array')->hasNoIn('VARIABLE')->inIs('LEFT')->atomIs('Assignation')->back('first')->raw('where( __.repeat( __.out("VARIABLE")).emit(hasLabel("Arrayappend")).times(' . self::MAX_LOOPING . ').count().is(eq(0)) )'); $this->prepareQuery(); // $a[1][] = 2; $this->atomIs('Array')->inIs('APPEND')->atomIs('Arrayappend')->back('first'); $this->prepareQuery(); // arguments : reference variable in a custom function $this->atomIs('Array')->savePropertyAs('rank', 'rank')->inIs('ARGUMENT')->inIs('ARGUMENTS')->hasNoIn('METHOD')->tokenIs(array('T_STRING', 'T_NS_SEPARATOR'))->functionDefinition()->inIs('NAME')->outIs('ARGUMENTS')->outIs('ARGUMENT')->samePropertyAs('rank', 'rank', true)->is('reference', true)->back('first'); $this->prepareQuery(); // function/methods definition : all modified by incoming values // simple variable $this->atomIs('Function')->outIs('ARGUMENTS')->outIs('ARGUMENT')->atomIs('Array'); $this->prepareQuery(); // PHP functions that are references $data = new Methods(); $functions = $data->getFunctionsReferenceArgs(); $references = array(); foreach ($functions as $function) { if (!isset($references[$function['position']])) { $references[$function['position']] = array('\\' . $function['function']); } else { $references[$function['position']][] = '\\' . $function['function']; } } foreach ($references as $position => $functions) { $this->atomIs('Array')->is('rank', $position)->inIs('ARGUMENT')->inIs('ARGUMENTS')->hasNoIn('METHOD')->atomIs('Functioncall')->tokenIs(array('T_STRING', 'T_NS_SEPARATOR', 'T_UNSET'))->fullnspathIs($functions)->back('first'); $this->prepareQuery(); } // Class constructors (__construct) $this->atomIs('Array')->savePropertyAs('rank', 'rank')->inIs('ARGUMENT')->inIs('ARGUMENTS')->hasNoIn('METHOD')->tokenIs(array('T_STRING', 'T_NS_SEPARATOR'))->atomIs('Functioncall')->hasIn('NEW')->classDefinition()->outIs('BLOCK')->outIs('ELEMENT')->analyzerIs('Classes/Constructor')->outIs('ARGUMENTS')->outIs('ARGUMENT')->samePropertyAs('rank', 'rank')->is('reference', true)->back('first'); $this->prepareQuery(); }
public function analyze() { $data = new Methods(); $methods = $data->getMethodsArgsInterval(); $argsMins = array(); $argsMaxs = array(); // Needs to finish the list of methods and their arguments. // Currently, classes are not checked. foreach ($methods as $method) { if ($method['args_min'] > 0) { $argsMins[$method['args_min']][] = $method['name']; } $argsMaxs[$method['args_max']][] = $method['name']; } // case for methods foreach ($argsMins as $nb => $f) { $this->atomIs(array('Methodcall', 'Staticmethodcall'))->outIs('METHOD')->codeIs($f)->outIs('ARGUMENTS')->isLess('count', $nb)->back('first'); $this->prepareQuery(); } foreach ($argsMaxs as $nb => $f) { $this->atomIs(array('Methodcall', 'Staticmethodcall'))->outIs('METHOD')->codeIs($f)->outIs('ARGUMENTS')->isMore('count', $nb)->back('first'); $this->prepareQuery(); } }
public function run() { $linksIn = Token::linksAsList(); // processing '\parent' fullnspath $query = <<<GREMLIN g.V().hasLabel("Identifier").filter{ it.get().value("fullnspath").toLowerCase() == "\\\\parent"} .where( __.until( and( hasLabel("Class"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("EXTENDS") ) .property('fullnspath', __.until( and( hasLabel("Class"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("EXTENDS").values("fullnspath") ) .where( __.until( and( hasLabel("Class"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("EXTENDS").in("DEFINITION") ) .addE('DEFINITION').from( __.until( and( hasLabel("Class"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("EXTENDS").in("DEFINITION") ) GREMLIN; $this->gremlin->query($query); display("\\parent to fullnspath\n"); // processing '\self' fullnspath $query = <<<GREMLIN g.V().hasLabel("Identifier").filter{ it.get().value("fullnspath").toLowerCase() == "\\\\self"} .where( __.until( and( hasLabel("Class", "Interface", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})) ) .property('fullnspath', __.until( and( hasLabel("Class", "Interface", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("NAME").values("fullnspath") ) .addE('DEFINITION').from( __.until( and( hasLabel("Class", "Interface", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})) ) GREMLIN; $this->gremlin->query($query); display('\\self to fullnspath'); // processing '\static' fullnspath $query = <<<GREMLIN g.V().hasLabel("Identifier").filter{ it.get().value("fullnspath").toLowerCase() == "\\\\static"} .where( __.until( and( hasLabel("Class", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})) ) .property('fullnspath', __.until( and( hasLabel("Class", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("NAME").values("fullnspath") ) .addE('DEFINITION').from( __.until( and( hasLabel("Class", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})) ) GREMLIN; $this->gremlin->query($query); display('\\static to fullnspath'); // Create link between Class constant and definition $query = <<<'GREMLIN' g.V().hasLabel('Staticconstant').as('first') .out('CONSTANT').sideEffect{name = it.get().value("code");}.select('first') .out('CLASS').hasLabel("Identifier", "Nsname").sideEffect{classe = it.get().value("fullnspath");}.in('DEFINITION') .where( __.sideEffect{classes = [];} .emit(hasLabel("Class")).repeat( out("EXTENDS").in("DEFINITION") ).times(15) .out("BLOCK").out("ELEMENT").hasLabel("Const").out("CONST").as('const') .out("NAME").filter{ it.get().value("code") == name; }.select('const') .sideEffect{classes.add(it.get()); } .fold() ) .map{classes[0]}.as('theClass') .addE('DEFINITION').from( 'first' ) GREMLIN; $this->gremlin->query($query); display('Create link between Class constant and definition'); // Create propertyname for Property Definitions $query = <<<GREMLIN g.V().hasLabel("Ppp", "Var").out("PPP").as("ppp") .coalesce( out("LEFT"), __.filter{ true } ) .sideEffect{ propertyname = it.get().value('code').toString().substring(1, it.get().value('code').size()); } .select("ppp") .sideEffect{ it.get().property('propertyname', propertyname); } GREMLIN; $this->gremlin->query($query); display('set propertyname'); // update fullnspath with fallback for functions $query = <<<GREMLIN g.V().hasLabel("Functioncall").as("a") .has("fullnspath", without('')) .has('token', within('T_STRING', 'T_NS_SEPARATOR')) .where( __.in("NEW", "METHOD").count().is(eq(0))) .sideEffect{ fullnspath = it.get().value("fullnspath")} .in('DEFINITION') .filter{ it.get().value("fullnspath") != fullnspath} .sideEffect{ fullnspath = it.get().value("fullnspath")} .select("a") .sideEffect{ it.get().property("fullnspath", fullnspath ); } GREMLIN; $this->gremlin->query($query); display('fallback for global functioncall'); // update fullnspath with fallback for functions $query = <<<GREMLIN g.V().hasLabel("Functioncall").has("fullnspath", without('')) .has('token', within('T_STRING', 'T_NS_SEPARATOR')) .where( __.in("NEW", "METHOD", "DEFINITION").count().is(eq(0))) .sideEffect{ fullnspath = it.get().vertices(OUT, 'NAME').next().value("fullnspath").toString().toLowerCase(); it.get().property("fullnspath", fullnspath ); } GREMLIN; $this->gremlin->query($query); display('refine functioncall fullnspath'); // update fullnspath with fallback for functions $query = <<<GREMLIN g.V().hasLabel("Identifier", "Nsname").as("a") .has("fullnspath", without('')) .has('token', within('T_STRING', 'T_NS_SEPARATOR')) .where( __.in("NEW", "METHOD", "NAME", "SUBNAME").count().is(eq(0))) .sideEffect{ fullnspath = it.get().value("fullnspath")} .in('DEFINITION').out("NAME") .filter{ it.get().value("fullnspath") != fullnspath} .sideEffect{ fullnspath = it.get().value("fullnspath")} .select("a") .sideEffect{ it.get().property("fullnspath", fullnspath ); } GREMLIN; $this->gremlin->query($query); display('fallback for global constants'); // fallback for PHP and ext, class, function, constant // update fullnspath with fallback for functions $pathDocs = $this->config->dir_root . '/data/analyzers.sqlite'; $docs = new Docs($pathDocs); $exts = $docs->listAllAnalyzer('Extensions'); $exts[] = 'php_constants'; $c = array(); $f = array(); foreach ($exts as $ext) { $inifile = str_replace('Extensions\\Ext', '', $ext) . '.ini'; $fullpath = $this->config->dir_root . '/data/' . $inifile; $iniFile = parse_ini_file($fullpath); if (!empty($iniFile['constants'][0])) { $c[] = $iniFile['constants']; } if (!empty($iniFile['functions'][0])) { $f[] = $iniFile['functions']; } } $constants = call_user_func_array('array_merge', $c); $constants = array_filter($constants, function ($x) { return strpos($x, '\\') === false; }); $constants = array_map('strtolower', $constants); $query = <<<GREMLIN g.V().hasLabel("Identifier").where( __.in("DEFINITION", "NEW", "USE", "NAME", "EXTENDS", "IMPLEMENTS", "CLASS", "CONST", "CONSTANT", "TYPEHINT", "FUNCTION", "GROUPUSE", "SUBNAME").count().is(eq(0)) ) .filter{ it.get().value("code").toLowerCase() in arg1 } .sideEffect{ fullnspath = "\\\\" + it.get().value("code").toLowerCase(); it.get().property("fullnspath", fullnspath); } GREMLIN; $this->gremlin->query($query, array('arg1' => $constants)); display('spot PHP / ext constants'); $query = 'g.V().hasLabel("Const").out("CONST").out("NAME").filter{ (it.get().value("fullnspath") =~ "^\\\\\\\\[^\\\\\\\\]+\\$" ).getCount() > 0 }.values("code")'; $constants = $this->gremlin->query($query); $constantsGlobal = $constants->results; $query = 'g.V().hasLabel("Const").out("CONST").out("NAME").filter{ (it.get().value("fullnspath") =~ "^\\\\\\\\[^\\\\\\\\]+\\$" ).getCount() == 0 }.values("fullnspath")'; $constants = $this->gremlin->query($query); $constantsDefinitions = $constants->results; $query = <<<GREMLIN g.V().hasLabel("Identifier").where( __.in("DEFINITION", "NEW", "USE", "NAME", "EXTENDS", "IMPLEMENTS", "CLASS", "CONST", "CONSTANT", "TYPEHINT", "FUNCTION", "GROUPUSE", "SUBNAME").count().is(eq(0)) ) .filter{ it.get().value("code") in arg1 } .filter{ !(it.get().value("fullnspath").toLowerCase() in arg2) } .sideEffect{ name = it.get().value("code"); } .sideEffect{ fullnspath = "\\\\" + it.get().value("code").toLowerCase(); it.get().property("fullnspath", fullnspath); }.addE("DEFINITION").from( g.V().hasLabel("Const").out("CONST").out("NAME").filter{ it.get().value("code") == name} ) GREMLIN; $this->gremlin->query($query, array('arg1' => $constantsGlobal, 'arg2' => $constantsDefinitions)); display('spot constants that falls back on global constants'); $functions = call_user_func_array('array_merge', $f); $functions = array_filter($functions, function ($x) { return strpos($x, '\\') === false; }); $functions = array_map('strtolower', $functions); $query = <<<GREMLIN g.V().hasLabel("Functioncall").not(has("token", "T_OPEN_TAG_WITH_ECHO")) .filter{ it.get().value("code").toLowerCase() in arg1 } .where( __.in("DEFINITION").count().is(eq(0)) ) .sideEffect{ fullnspath = "\\\\" + it.get().value("code").toLowerCase(); it.get().property("fullnspath", fullnspath); } GREMLIN; $this->gremlin->query($query, array('arg1' => $functions)); display('mark PHP native functions call'); // Define-style constant definitions $query = <<<GREMLIN g.V().hasLabel("Functioncall").has("fullnspath", "\\\\define") .out("ARGUMENTS").out("ARGUMENT").has("rank", 0) .hasLabel("String").has("noDelimiter") .map{ s = it.get().value("noDelimiter").toString().toLowerCase(); if ( s.substring(0,1) != "\\\\") { s = "\\\\" + s; } it.get().property("fullnspath", s); s; }.unique(); GREMLIN; $constants = $this->gremlin->query($query); $constants = $constants->results; if (!empty($constants)) { // First round, with full ns path $query = <<<GREMLIN g.V().hasLabel("Identifier", "Nsname") .where( __.in("NAME", "SUBNAME").count().is(eq(0)) ) .filter{ it.get().value("fullnspath") in arg1 }.sideEffect{name = it.get().value("fullnspath"); } .addE('DEFINITION') .from( g.V().hasLabel("Functioncall").has("fullnspath", "\\\\define") .out("ARGUMENTS").as("a").out("ARGUMENT").has("rank", 0).hasLabel("String") .filter{ it.get().value("fullnspath") == name}.select('a') ) GREMLIN; $res = $this->gremlin->query($query, array('arg1' => $constants)); // Second round, with fallback to global constants $query = <<<GREMLIN g.V().hasLabel("Identifier", "Nsname") .where( __.in("NAME", "SUBNAME").count().is(eq(0)) ) .where( __.in("DEFINITION").count().is(eq(0)) ) .filter{ name = "\\\\" + it.get().value("fullcode").toString().toLowerCase(); name in arg1 } .addE('DEFINITION') .from( g.V().hasLabel("Functioncall").has("fullnspath", "\\\\define") .out("ARGUMENTS").as("a").out("ARGUMENT").has("rank", 0).hasLabel("String") .filter{ it.get().value("fullnspath") == name}.select('a') ) GREMLIN; $res = $this->gremlin->query($query, array('arg1' => $constants)); // TODO : handle case-insensitive display('Link constant definitions'); } else { display('Link constant definitions : skipping.'); } display('Mark literal expressions as constants'); $query = <<<GREMLIN g.V().hasLabel("Integer", "Boolean", "Real", "Null", "Void", "InlineHtml", "Magicconstant", "Staticconstant", "Void") .sideEffect{ it.get().property("constant", true); } GREMLIN; $this->gremlin->query($query); $query = <<<GREMLIN g.V().hasLabel("String").where( __.out("CONCAT").count().is(eq(0))) .sideEffect{ it.get().property("constant", true); } GREMLIN; $this->gremlin->query($query); $query = <<<GREMLIN g.V().hasLabel("Identifier", "Nsname").not(hasLabel("Functioncall")) .sideEffect{ it.get().property("constant", true); } GREMLIN; $this->gremlin->query($query); $data = new Methods(); $deterministFunctions = $data->getDeterministFunctions(); $deterministFunctions = array_map(function ($x) { return '\\' . $x; }, $deterministFunctions); for ($i = 0; $i < 3; ++$i) { // Cases for Structures (all sub element are constante => structure is constante) $structures = array('Addition' => array('LEFT', 'RIGHT'), 'Multiplication' => array('LEFT', 'RIGHT'), 'Bitshift' => array('LEFT', 'RIGHT'), 'Logical' => array('LEFT', 'RIGHT'), 'Power' => array('LEFT', 'RIGHT'), 'Keyvalue' => array('KEY', 'VALUE'), 'Arguments' => array('ARGUMENT'), 'Sequence' => array('ELEMENT'), 'Break' => array('BREAK'), 'Continue' => array('CONTINUE'), 'Return' => array('RETURN'), 'Ternary' => array('CONDITION', 'THEN', 'ELSE'), 'Comparison' => array('LEFT', 'RIGHT'), 'Noscream' => array('AT'), 'Not' => array('NOT'), 'Parenthesis' => array('CODE'), 'Concatenation' => array('CONCAT'), 'String' => array('CONCAT')); foreach ($structures as $atom => $links) { $linksList = "'" . implode("', '", $links) . "'"; $query = <<<GREMLIN g.V().hasLabel("{$atom}").where( __.out({$linksList}).not(has("constant", true)).count().is(eq(0)) ) .sideEffect{ it.get().property("constant", true);} GREMLIN; $this->gremlin->query($query); } $query = <<<GREMLIN g.V().hasLabel("Functioncall").filter{ it.get().value("fullnspath") in arg1} .where( __.out("ARGUMENTS").out("ARGUMENT").not(has("constant", true)).count().is(eq(0)) ) .sideEffect{ it.get().property("constant", true);} GREMLIN; $this->gremlin->query($query, array('arg1' => $deterministFunctions)); } display('Mark constants expressions'); $query = <<<GREMLIN g.V().hasLabel("Variable").has("code", "\\\$GLOBALS").in("VARIABLE").hasLabel("Array").as("var") .out("INDEX").hasLabel("String") .sideEffect{ varname = '\$' + it.get().value('noDelimiter'); it.get().property("globalvar", varname);} GREMLIN; $this->gremlin->query($query); display('Mark constants expressions'); }
protected function generateBugfixes() { $table = ''; $data = new Methods(); $bugfixes = $data->getBugFixes(); $found = $this->sqlite->query('SELECT * FROM results WHERE analyzer = "Php/MiddleVersion"'); $reported = array(); $info = array(); $rows = array(); while ($row = $found->fetchArray()) { $rows[strtolower(substr($row['fullcode'], 0, strpos($row['fullcode'], '(')))] = $row; } foreach ($bugfixes as $bugfix) { if (!empty($bugfix['function'])) { if (!isset($rows[$bugfix['function']])) { continue; } $cve = $this->Bugfixes_cve($bugfix['cve']); $table .= '<tr> <td>' . $bugfix['title'] . '</td> <td>' . ($bugfix['solvedIn71'] ? $bugfix['solvedIn71'] : '-') . '</td> <td>' . ($bugfix['solvedIn70'] ? $bugfix['solvedIn70'] : '-') . '</td> <td>' . ($bugfix['solvedIn56'] ? $bugfix['solvedIn56'] : '-') . '</td> <td>' . ($bugfix['solvedIn55'] ? $bugfix['solvedIn55'] : '-') . '</td> <td>' . ($bugfix['solvedInDev'] ? $bugfix['solvedInDev'] : '-') . '</td> <td><a href="https://bugs.php.net/bug.php?id=' . $bugfix['bugs'] . '">#' . $bugfix['bugs'] . '</a></td> <td>' . $cve . '</td> </tr>'; } elseif (!empty($bugfix['analyzer'])) { $subanalyze = $this->sqlite->querySingle('SELECT count FROM resultsCounts WHERE analyzer = "' . $bugfix['analyzer'] . '"'); $cve = $this->Bugfixes_cve($bugfix['cve']); if ($subanalyze == 0) { continue; } $table .= '<tr> <td>' . $bugfix['title'] . '</td> <td>' . ($bugfix['solvedIn71'] ? $bugfix['solvedIn71'] : '-') . '</td> <td>' . ($bugfix['solvedIn70'] ? $bugfix['solvedIn70'] : '-') . '</td> <td>' . ($bugfix['solvedIn56'] ? $bugfix['solvedIn56'] : '-') . '</td> <td>' . ($bugfix['solvedIn55'] ? $bugfix['solvedIn55'] : '-') . '</td> <td>' . ($bugfix['solvedInDev'] ? $bugfix['solvedInDev'] : '-') . '</td> <td><a href="https://bugs.php.net/bug.php?id=' . $bugfix['bugs'] . '">#' . $bugfix['bugs'] . '</a></td> <td>' . $cve . '</td> </tr>'; } else { continue; // ignore. Possibly some mis-configuration } } $html = $this->getBasedPage('bugfixes'); $html = $this->injectBloc($html, 'BUG_FIXES', $table); $this->putBasedPage('bugfixes', $html); }
protected function Bugfixes() { $css = new \Stdclass(); $css->displayTitles = true; $css->titles = array('Title', 'Solved In 7.0', 'Solved In 5.6', 'Solved In 5.5', 'Solved In php-src', 'bugs.php.net', 'CVE'); $css->readOrder = $css->titles; $data = new Methods(); $bugfixes = $data->getBugFixes(); $found = $this->dump->query('SELECT * FROM results WHERE analyzer = "Php/MiddleVersion"'); $reported = array(); $info = array(); $rows = array(); while ($row = $found->fetchArray()) { $rows[strtolower(substr($row['fullcode'], 0, strpos($row['fullcode'], '(')))] = $row; } foreach ($bugfixes as $bugfix) { if (!empty($bugfix['function'])) { if (!isset($rows[$bugfix['function']])) { continue; } $cve = $this->Bugfixes_cve($bugfix['cve']); $info[] = array('title' => $bugfix['title'], 'solvedIn70' => $bugfix['solvedIn70'] ? $bugfix['solvedIn70'] : '-', 'solvedIn56' => $bugfix['solvedIn56'] ? $bugfix['solvedIn56'] : '-', 'solvedIn55' => $bugfix['solvedIn55'] ? $bugfix['solvedIn55'] : '-', 'solvedInDev' => $bugfix['solvedInDev'] ? $bugfix['solvedInDev'] : '-', 'bug' => '<a href="https://bugs.php.net/bug.php?id=' . $bugfix['bugs'] . '">#' . $bugfix['bugs'] . '</a>', 'cve' => $cve); } elseif (!empty($bugfix['analyzer'])) { $subanalyze = $this->dump->querySingle('SELECT COUNT(*) FROM results WHERE analyzer = "' . $bugfix['analyzer'] . '"'); $cve = $this->Bugfixes_cve($bugfix['cve']); if ($subanalyze > 0) { $info[] = array('title' => $bugfix['title'], 'solvedIn70' => $bugfix['solvedIn70'] ? $bugfix['solvedIn70'] : '-', 'solvedIn56' => $bugfix['solvedIn56'] ? $bugfix['solvedIn56'] : '-', 'solvedIn55' => $bugfix['solvedIn55'] ? $bugfix['solvedIn55'] : '-', 'solvedInDev' => $bugfix['solvedInDev'] ? $bugfix['solvedInDev'] : '-', 'bug' => 'ext/' . $bugfix['extension'], 'cve' => $cve); } } else { continue; // ignore. Possibly some mis-configuration } } return $this->formatCompilationTable($info, $css); }