This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * See class comment |
||
4 | * |
||
5 | * PHP Version 5 |
||
6 | * |
||
7 | * @category Netresearch |
||
8 | * @package Netresearch\Kite |
||
9 | * @subpackage ExpressionLanguage |
||
10 | * @author Christian Opitz <[email protected]> |
||
11 | * @license http://www.netresearch.de Netresearch Copyright |
||
12 | * @link http://www.netresearch.de |
||
13 | */ |
||
14 | |||
15 | namespace Netresearch\Kite\ExpressionLanguage; |
||
16 | use Netresearch\Kite\Task; |
||
17 | |||
18 | use Symfony\Component\Console\Question\ChoiceQuestion; |
||
19 | use Symfony\Component\Console\Question\ConfirmationQuestion; |
||
20 | use Symfony\Component\Console\Question\Question; |
||
21 | use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface; |
||
22 | |||
23 | /** |
||
24 | * Extension of Symfonies expression language to inject our custom |
||
25 | * lexer and register some functions |
||
26 | * |
||
27 | * @category Netresearch |
||
28 | * @package Netresearch\Kite |
||
29 | * @subpackage ExpressionLanguage |
||
30 | * @author Christian Opitz <[email protected]> |
||
31 | * @license http://www.netresearch.de Netresearch Copyright |
||
32 | * @link http://www.netresearch.de |
||
33 | */ |
||
34 | class ExpressionLanguage extends \Symfony\Component\ExpressionLanguage\ExpressionLanguage |
||
35 | { |
||
36 | /** |
||
37 | * @var array |
||
38 | */ |
||
39 | protected $expressionResults = []; |
||
40 | |||
41 | /** |
||
42 | * @var string |
||
43 | */ |
||
44 | const VARIABLES_KEY = 'variables'; |
||
45 | |||
46 | /** |
||
47 | * ExpressionLanguage constructor. |
||
48 | * |
||
49 | * @param ParserCacheInterface|null $cache The cache |
||
50 | * @param array $providers Providers |
||
51 | */ |
||
52 | public function __construct(ParserCacheInterface $cache = null, array $providers = array()) |
||
53 | { |
||
54 | parent::__construct($cache, $providers); |
||
55 | |||
56 | $reflectionProperty = new \ReflectionProperty('\Symfony\Component\ExpressionLanguage\ExpressionLanguage', 'lexer'); |
||
57 | $reflectionProperty->setAccessible(true); |
||
58 | $reflectionProperty->setValue($this, new Lexer()); |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * Reevaluate parents evaluation results as expressions could be nested |
||
63 | * |
||
64 | * Don't parse expression strings which were the final result of an evaluation |
||
65 | * ( As for example, given a variable "char" that is "\{", |
||
66 | * the result of "{char}" would be "{". Reevaluating this is 1. not intended |
||
67 | * and would 2. lead to an error ) |
||
68 | * |
||
69 | * @param string|\Symfony\Component\ExpressionLanguage\Expression $expression The expression |
||
70 | * @param array $values The values |
||
71 | * |
||
72 | * @return string|mixed |
||
73 | */ |
||
74 | public function evaluate($expression, $values = []) |
||
75 | { |
||
76 | if (is_string($expression) |
||
77 | && !in_array($expression, $this->expressionResults, true) |
||
78 | && preg_match($couldBeExpressionPattern = '/(^|[^\\\\])\{/', $expression) |
||
79 | ) { |
||
80 | do { |
||
81 | $expression = parent::evaluate($expression, $values); |
||
82 | if (!is_string($expression)) { |
||
83 | break; |
||
84 | } |
||
85 | if (!preg_match($couldBeExpressionPattern, $expression)) { |
||
86 | $expression = str_replace(['\\{', '\\}'], ['{', '}'], $expression); |
||
87 | if (strpos($expression, '{') !== false) { |
||
88 | $this->expressionResults[] = $expression; |
||
89 | } |
||
90 | break; |
||
91 | } |
||
92 | } while (true); |
||
93 | } |
||
94 | return $expression; |
||
95 | } |
||
96 | |||
97 | |||
98 | /** |
||
99 | * Ask a question |
||
100 | * |
||
101 | * @param Task $task The task on which the question was asked |
||
102 | * @param Question $question The question |
||
103 | * |
||
104 | * @return mixed The answer |
||
105 | */ |
||
106 | protected function ask(Task $task, $question) |
||
107 | { |
||
108 | $console = $task->console; |
||
109 | return $console->getHelper('question')->ask( |
||
0 ignored issues
–
show
|
|||
110 | $console->getInput(), |
||
111 | $console->getOutput(), |
||
112 | $question |
||
113 | ); |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Register functions |
||
118 | * |
||
119 | * @return void |
||
120 | */ |
||
121 | protected function registerFunctions() |
||
122 | { |
||
123 | parent::registerFunctions(); |
||
124 | $functions = [ |
||
125 | 'call' => function (array $values, $function) { |
||
126 | $args = array_slice(func_get_args(), 2); |
||
127 | if (array_key_exists($function, $this->functions)) { |
||
128 | array_unshift($args, $values); |
||
129 | $function = $this->functions[$function]['evaluator']; |
||
130 | } |
||
131 | return call_user_func_array($function, $args); |
||
132 | }, |
||
133 | 'isset' => function (array $values, $var) { |
||
134 | return $values[self::VARIABLES_KEY]->has($var); |
||
135 | }, |
||
136 | 'empty' => function (array $values, $var) { |
||
137 | return !$values[self::VARIABLES_KEY]->has($var) || !$values[self::VARIABLES_KEY]->get($var); |
||
138 | }, |
||
139 | 'get' => function (array $values, $var) { |
||
140 | return $values[self::VARIABLES_KEY]->get($var); |
||
141 | }, |
||
142 | 'set' => function (array $values, $var, $value) { |
||
143 | $values[self::VARIABLES_KEY]->set($var, $value); |
||
144 | return $value; |
||
145 | }, |
||
146 | 'confirm' => function (array $values, $question) { |
||
147 | return $this->ask($values[self::VARIABLES_KEY], new ConfirmationQuestion("<question>$question</question> [y] ")); |
||
148 | }, |
||
149 | 'answer' => function (array $values, $question) { |
||
150 | return $this->ask($values[self::VARIABLES_KEY], new Question("<question>$question</question> ")); |
||
151 | }, |
||
152 | 'choose' => function (array $values, $question) { |
||
153 | return $this->ask($values[self::VARIABLES_KEY], new Question("<question>$question</question> ")); |
||
154 | }, |
||
155 | 'replace' => function (array $values, $search, $replace, $subject, $regex = false) { |
||
156 | $values[self::VARIABLES_KEY]->console->output( |
||
157 | '<warning>Expression language function "replace" is deprecated ' |
||
158 | . 'and will be removed in 1.6.0 - use preg_replace or str_replace</warning>' |
||
159 | ); |
||
160 | if ($regex) { |
||
161 | return preg_replace($search, $replace, $subject); |
||
162 | } else { |
||
163 | return str_replace($search, $replace, $subject); |
||
164 | } |
||
165 | }, |
||
166 | ]; |
||
167 | foreach ($functions as $name => $function) { |
||
168 | $this->register( |
||
169 | $name, |
||
170 | function () { |
||
171 | |||
172 | }, |
||
173 | $function |
||
174 | ); |
||
175 | } |
||
176 | } |
||
177 | } |
||
178 | ?> |
||
179 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: