public function leaveNode($node) { /** * PHP 4 style constructors * * @see http://php.net/manual/en/migration70.deprecated.php#migration70.deprecated.php4-constructors */ if ($node instanceof Stmt\ClassMethod && $node->migName == $this->visitor->getClass()->name) { $this->addSpot('DEPRECATED', true, 'PHP 4 style constructor is deprecated'); /** * password_hash() salt option * * @see http://php.net/manual/en/migration70.deprecated.php#migration70.deprecated.pwshash-salt-option */ } elseif ($node instanceof Expr\FuncCall && ParserHelper::isSameFunc($node->migName, 'password_hash') && isset($node->args[2])) { $this->addSpot('DEPRECATED', false, 'salt option for password_hash() is deprecated'); /** * LDAP deprecations * * @see http://php.net/manual/en/migration70.deprecated.php#migration70.deprecated.ldap */ } elseif ($node instanceof Expr\FuncCall && ParserHelper::isSameFunc($node->migName, 'ldap_sort')) { $this->addSpot('DEPRECATED', true, 'ldap_sort() is deprecated'); } }
public function leaveNode($node) { /** * set_exception_handler() is no longer guaranteed to receive Exception * objects * * @see http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.error-handling */ if (!$node instanceof Expr\FuncCall || !ParserHelper::isSameFunc($node->name, 'set_exception_handler') || !isset($node->args[0])) { return; } $affected = true; $certain = false; $callback = $node->args[0]->value; if ($callback instanceof Expr\Closure) { if (!isset($callback->params[0]) || !isset($callback->params[0]->type)) { $affected = false; $certain = true; } elseif (ParserHelper::isSameClass($callback->params[0]->type, 'Exception')) { $affected = true; $certain = true; } } if ($affected) { $this->addSpot('WARNING', $certain, 'set_exception_handler() is no longer guaranteed to receive Exception objects'); } }
public function leaveNode($node) { if ($node instanceof Expr\FuncCall && $this->mysqlTable->has($node->name)) { /** * {Description} * The original MySQL extension is now deprecated, and will generate * E_DEPRECATED errors when connecting to a database. Instead, use the * MySQLi or PDO_MySQL extensions. * * {Reference} * http://php.net/manual/en/migration55.deprecated.php#migration55.deprecated.mysql */ $this->addSpot('DEPRECATED', true, 'The original MySQL extension is deprecated, use MySQLi or PDO_MySQL extensions instead'); } elseif ($node instanceof Expr\FuncCall && ParserHelper::isSameFunc($node->name, 'preg_replace')) { /** * {Description} * The preg_replace() /e modifier is now deprecated. Instead, use the * preg_replace_callback() function. * * {Reference} * http://php.net/manual/en/migration55.deprecated.php#migration55.deprecated.preg-replace-e */ $affected = true; $certain = false; if (!isset($node->args[0])) { return; } $pattern = $node->args[0]->value; // TODO: shoud be full tested // Read right-most if concat, encapsed if ($pattern instanceof Expr\BinaryOp\Concat) { $pattern = $pattern->right; } if ($pattern instanceof Scalar\Encapsed) { $pattern = end($pattern->parts); } // Extract to string if ($pattern instanceof Scalar\String_ || $pattern instanceof Scalar\EncapsedStringPart) { $pattern = $pattern->value; } // Guess whether e in modifier if (is_string($pattern)) { $modifier = strrchr($pattern, '/'); $certain = $affected = strpos($modifier, 'e') !== false; } if ($affected) { $this->addSpot('DEPRECATED', $certain, 'preg_replace() /e modifier is deprecated, use preg_replace_callback() instead'); } } elseif ($node instanceof Expr\FuncCall && $this->funcTable->has($node->name)) { /** * TODO: how to check IntlDateFormatter::setTimeZoneId * * {Reference} * http://php.net/manual/en/migration55.deprecated.php#migration55.deprecated.intl * http://php.net/manual/en/migration55.deprecated.php#migration55.deprecated.mcrypt */ $this->addSpot('DEPRECATED', true, 'Function ' . $node->name . '() is deprecated'); } }
public function leaveNode($node) { if (!$node instanceof Stmt\Class_) { return; } foreach ($node->getMethods() as $mnode) { if ((!$mnode->isPublic() || $mnode->isStatic()) && $this->funcTable->has($mnode->name)) { $this->emitNonPub($mnode); } elseif (ParserHelper::isSameFunc($mnode->name, '__toString') && count($mnode->params) > 0) { $this->emitToString($mnode); } } }
public function leaveNode($node) { // json_decode() if ($node instanceof Expr\FuncCall && ParserHelper::isSameFunc($node->name, 'json_decode')) { /** * {Description} * json_decode() now rejects non-lowercase variants of the JSON * literals true, false and null at all times, as per the JSON * specification, and sets json_last_error() accordingly. * Previously, inputs to json_decode() that consisted solely of one * of these values in upper or mixed case were accepted. * * This change will only affect cases where invalid JSON was being * passed to json_decode(): valid JSON input is unaffected and will * continue to be parsed normally. * * {Reference} * http://php.net/manual/en/migration56.incompatible.php#migration56.incompatible.json-decode */ $this->addSpot('NOTICE', false, 'json_decode() rejects non-lowercase variants of true, false, null'); // GMP } elseif ($node instanceof Expr\FuncCall && $this->gmpTable->has($node->name)) { /** * {Description} * GMP resources are now objects. The functional API implemented in * the GMP extension has not changed, and code should run * unmodified unless it checks explicitly for a resource using * is_resource() or similar. * * {Reference} * http://php.net/manual/en/migration56.incompatible.php#migration56.incompatible.gmp */ $this->addSpot('NOTICE', false, 'GMP resource is now object, do not use is_resource() to test'); // Mcrypt } elseif ($node instanceof Expr\FuncCall && $this->mcryptTable->has($node->name)) { /** * {Description} * mcrypt_encrypt(), mcrypt_decrypt(), mcrypt_cbc(), mcrypt_cfb(), * mcrypt_ecb(), mcrypt_generic() and mcrypt_ofb() will no longer * accept keys or IVs with incorrect sizes, and block cipher modes * that require IVs will now fail if an IV isn't provided. * * {Reference} * http://php.net/manual/en/migration56.incompatible.php#migration56.incompatible.mcrypt */ $this->addSpot('NOTICE', false, $node->name . '() no longer accept keys or IVs with incorrect size'); } }
public function leaveNode($node) { $non_public = []; $has_magic_call = false; if ($node instanceof Stmt\Class_) { foreach ($node->getMethods() as $mnode) { if (ParserHelper::isSameFunc($mnode->name, '__call')) { $has_magic_call = true; $magic_node = $mnode; } elseif (!$mnode->isPublic()) { $non_public[] = $mnode->name; } } } if ($has_magic_call && $non_public) { $this->emitSpot($magic_node, $non_public); } }
public function leaveNode($node) { /** * {Description} * These words have special meaning in PHP. Some of them represent * things which look like functions, some look like constants, and so * on - but they're not, really: they are language constructs. You * cannot use any of the following words as constants, class names, * function or method names. Using them as variable names is generally * OK, but could lead to confusion. * * {Reference} * http://php.net/manual/en/reserved.keywords.php */ $name = null; if ($node instanceof Stmt\ClassLike || $node instanceof Stmt\Function_ || $node instanceof Stmt\ClassMethod || $node instanceof Expr\MethodCall || $node instanceof Expr\StaticCall || $node instanceof Expr\ConstFetch || $node instanceof Expr\FuncCall && !ParserHelper::isDynamicCall($node)) { $name = $node->migName; } if (!is_null($name) && $this->wordTable->has($name)) { $this->addSpot('FATAL', true, 'Keyword "' . $name . '" is reserved'); } }
public function leaveNode($node) { /** * {Description} * Changes were made to pack() and unpack() to make them more compatible with Perl: * * pack() now supports the "Z" format code, which behaves identically * to "a". * * unpack() now support the "Z" format code for NULL padded strings, * and behaves as "a" did in previous versions: it will strip trailing * NULL bytes. * * unpack() now keeps trailing NULL bytes when the "a" format code is * used. * * unpack() now strips all trailing ASCII whitespace when the "A" * format code is used. * * {Reference} * http://php.net/manual/en/migration55.incompatible.php#migration55.incompatible.pack */ if ($node instanceof Expr\FuncCall && ParserHelper::isSameFunc($node->name, 'unpack')) { $affected = true; $certain = false; if (!isset($node->args[0])) { return; } $format = $node->args[0]->value; // Try to check arg $format if ($format instanceof Scalar\String_) { // using stripos for both "a" and "A" $certain = $affected = stripos($format->value, 'a') !== false; } if ($affected) { $this->addSpot('WARNING', $certain, 'Behavior of pack() with "a", "A" in format is changed'); } } }
public function leaveNode($node) { // array_combine() if ($node instanceof Expr\FuncCall && ParserHelper::isSameFunc($node->name, 'array_combine')) { /** * {Description} * array_combine() now returns array() instead of FALSE when two empty * arrays are provided as parameters. * * {Reference} * http://php.net/manual/en/migration54.incompatible.php */ $this->addSpot('NOTICE', false, 'array_combine() now returns array() instead of FALSE when two empty arrays given'); // ob_start() } elseif ($node instanceof Expr\FuncCall && ParserHelper::isSameFunc($node->name, 'ob_start') && isset($node->args[2])) { /** * {Description} * The third parameter of ob_start() has changed from boolean erase * to integer flags. Note that code that explicitly set erase to * FALSE will no longer behave as expected in PHP 5.4: please * follow this example to write code that is compatible with PHP * 5.3 and 5.4. * * {Reference} * http://php.net/manual/en/function.ob-start.php * http://php.net/manual/en/migration54.incompatible.php */ $this->addSpot('WARNING', true, 'The third parameter of ob_start() has changed'); } elseif ($node instanceof Expr\FuncCall && (ParserHelper::isSameFunc($node->name, 'htmlentities') || ParserHelper::isSameFunc($node->name, 'htmlspecialchars'))) { /** * {Description} * If you use htmlentities() with asian character sets, it works * like htmlspecialchars() - this has always been the case in * previous versions of PHP, but now an E_STRICT level error is * emitted. * * The default character set for htmlspecialchars() and * htmlentities() is now UTF-8, instead of ISO-8859-1. Note that * changing your output charset via the default_charset * configuration setting does not affect * htmlspecialchars/htmlentities unless you are passing "" (an * empty string) as the encoding parameter to your * htmlspecialchars()/htmlentities() calls. Generally we do not * recommend doing this because you should be able to change your * output charset without affecting the runtime charset used by * these functions. The safest approach is to explicitly set the * charset on each call to htmlspecialchars() and htmlentities(). * * {Reference} * http://php.net/manual/en/function.htmlentities.php * http://php.net/manual/en/function.htmlspecialchars.php * http://php.net/manual/en/migration54.other.php * http://php.net/manual/en/migration54.incompatible.php */ $level = false; $msgbox = []; if (ParserHelper::isSameFunc($node->name, 'htmlentities')) { $level = 'WARNING'; $msgbox[] = 'won\'t encode asian character sets'; } if (!isset($node->args[2])) { // Set encoding $level = 'NOTICE'; $msgbox[] = 'default encoding was changed'; } if ($level) { $this->addSpot($level, false, $node->name . '() ' . implode(', ', $msgbox)); } } }
public function leaveNode($node) { if ($node instanceof Expr\FuncCall) { if (ParserHelper::isSameFunc($node->name, 'clearstatcache')) { /** * {Description} * clearstatcache() no longer clears the realpath cache by default. * * {Reference} * http://php.net/manual/en/migration53.incompatible.php */ $this->addSpot('NOTICE', false, 'clearstatcache() no longer clears the realpath cache by default'); } elseif (ParserHelper::isSameFunc($node->name, 'realpath')) { /** * {Description} * realpath() is now fully platform-independent. Consequence of * this is that invalid relative paths such as __FILE__ . "/../x" * do not work anymore. * Prior to this release, if only the last path component did not * exist, realpath() would not fail on *BSD systems. realpath() now * fails in this case. * * {Reference} * http://php.net/manual/en/function.realpath.php * http://php.net/manual/en/migration53.incompatible.php */ $this->addSpot('NOTICE', false, 'realpath() is now fully platform-independent, especially on *BSD.'); } elseif ($this->arrFuncTable->has($node->name)) { /** * {Description} * The array functions natsort(), natcasesort(), usort(), uasort(), * uksort(), array_flip(), and array_unique() no longer accept * objects passed as arguments. To apply these functions to an * object, cast the object to an array first. * * {Reference} * http://php.net/manual/en/migration53.incompatible.php */ $this->addSpot('NOTICE', false, sprintf('%s() no longer accept objects passed as arguments', $node->name)); } elseif (ParserHelper::isSameFunc($node->name, 'call_user_func_array')) { /** * {Description} * call_user_func_array() no longer accepts null as a second * parameter and calls the function. It now emits a warning and * does not call the function. * * {Reference} * User Contributed Notes by Chris Bolt * http://php.net/manual/en/migration53.incompatible.php */ if (isset($node->args[1]) && !$node->args[1]->value instanceof Expr\Array_) { $this->addSpot('NOTICE', false, sprintf('%s() no longer accept non-array passed as arguments', $node->name)); } } elseif (ParserHelper::isSameFunc($node->name, 'gd_info')) { /** * {Description} * Image Processing and GD The "JPG Support" index returned from * gd_info() has been renamed to "JPEG Support". * * {Reference} * http://php.net/manual/en/migration53.extensions-other.php */ $this->addSpot('NOTICE', false, 'gd_info() JPG Support attribute renamed to JPEG Support'); } } }
/** * Conditional checking */ protected function isConditionalDeclare($node, $testfunc) { if (!$node instanceof Stmt\If_ || !$node->cond instanceof Expr\BooleanNot) { return false; } $expr = $node->cond->expr; return $expr instanceof Expr\FuncCall && ParserHelper::isSameFunc($expr->migName, $testfunc); }
protected function populateCall($node, $type) { if (ParserHelper::isDynamicCall($node)) { return; } $posbit = $this->positionByValue($node); if (!$posbit) { return; } if ($type == 'func') { $callname = $node->name; } elseif ($type == 'static') { $class = $node->class->toString(); if ($class == 'self' && $this->visitor->inClass()) { $class = $this->visitor->getClassName(); } $callname = $class . '::' . $node->name; } elseif ($type == 'method') { if ($node->var instanceof Expr\Variable && $node->var->name == 'this' && $this->visitor->inClass()) { $oname = $this->visitor->getClassName(); } else { $oname = ''; } $callname = $oname . '->' . $node->name; } $this->callList[] = ['name' => $callname, 'pos' => $posbit, 'file' => $this->visitor->getFile(), 'line' => $node->getLine()]; }