Skip to content

Commit

Permalink
Merge pull request #12 from vkill/ignore-json-throw-on-error
Browse files Browse the repository at this point in the history
Ignore json_decode and json_encode when use JSON_THROW_ON_ERROR option
  • Loading branch information
moufmouf authored Jul 15, 2019
2 parents 8bb68fb + e7fa736 commit 70bfb67
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/Rules/UseSafeFunctionsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
use PHPStan\Rules\Rule;
use PHPStan\ShouldNotHappenException;
use TheCodingMachine\Safe\PHPStan\Utils\FunctionListLoader;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;

/**
* This rule checks that no superglobals are used in code.
Expand All @@ -35,9 +38,53 @@ public function processNode(Node $node, Scope $scope): array
$unsafeFunctions = FunctionListLoader::getFunctionList();

if (isset($unsafeFunctions[$functionName])) {
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
if ($functionName === "json_decode") {
if (count($node->args) == 4) {
if ($this->argValueIncludeJSONTHROWONERROR($node->args[3])) {
return [];
}
}
}
if ($functionName === "json_encode") {
if (count($node->args) >= 2) {
if ($this->argValueIncludeJSONTHROWONERROR($node->args[1])) {
return [];
}
}
}
}

return ["Function $functionName is unsafe to use. It can return FALSE instead of throwing an exception. Please add 'use function Safe\\$functionName;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library."];
}

return [];
}

private function argValueIncludeJSONTHROWONERROR(Arg $arg): bool
{
$parseValue = function ($expr, array $options) use (&$parseValue): array {
if ($expr instanceof Expr\BinaryOp\BitwiseOr) {
return array_merge($parseValue($expr->left, $options), $parseValue($expr->right, $options));
} elseif ($expr instanceof Expr\ConstFetch) {
return array_merge($options, $expr->name->parts);
} elseif ($expr instanceof Scalar\LNumber) {
return array_merge($options, [$expr->value]);
} else {
return $options;
}
};
$options = $parseValue($arg->value, []);

if (in_array("JSON_THROW_ON_ERROR", $options)) {
return true;
}

return in_array(true, array_map(function ($element) {
// JSON_THROW_ON_ERROR == 4194304
return ($element & 4194304) == 4194304;
}, array_filter($options, function ($element) {
return is_int($element);
})));
}
}
18 changes: 18 additions & 0 deletions tests/Rules/UseSafeFunctionsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,22 @@ public function testExprCall()
{
$this->analyse([__DIR__ . '/data/undirect_call.php'], []);
}

public function testJSONDecodeNoCatchSafe()
{
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
$this->analyse([__DIR__ . '/data/safe_json_decode_for_7.3.0.php'], []);
} else {
$this->assertTrue(true);
}
}

public function testJSONEncodeNoCatchSafe()
{
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
$this->analyse([__DIR__ . '/data/safe_json_encode_for_7.3.0.php'], []);
} else {
$this->assertTrue(true);
}
}
}
9 changes: 9 additions & 0 deletions tests/Rules/data/safe_json_decode_for_7.3.0.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

json_decode("{}", true, 512, JSON_THROW_ON_ERROR);
json_decode("{}", true, 512, JSON_INVALID_UTF8_IGNORE | JSON_THROW_ON_ERROR);
json_decode("{}", true, 512, JSON_INVALID_UTF8_IGNORE | JSON_OBJECT_AS_ARRAY | JSON_THROW_ON_ERROR);

json_decode("{}", true, 512, 4194304);
json_decode("{}", true, 512, 1048576 | 4194304);
json_decode("{}", true, 512, 1048576 | 1 | 4194304);
5 changes: 5 additions & 0 deletions tests/Rules/data/safe_json_encode_for_7.3.0.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

json_encode([], JSON_THROW_ON_ERROR, 512);
json_encode([], JSON_FORCE_OBJECT | JSON_THROW_ON_ERROR, 512);
json_encode([], JSON_FORCE_OBJECT | JSON_INVALID_UTF8_IGNORE | JSON_THROW_ON_ERROR, 512);

0 comments on commit 70bfb67

Please sign in to comment.