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 | * @link https://github.com/old-town/old-town-workflow |
||
4 | * @author Malofeykin Andrey <[email protected]> |
||
5 | */ |
||
6 | namespace OldTown\Workflow\Config; |
||
7 | |||
8 | use OldTown\Workflow\Exception\FactoryException; |
||
9 | use OldTown\Workflow\Exception\InvalidParsingWorkflowException; |
||
10 | use OldTown\Workflow\Loader\UrlWorkflowFactory; |
||
11 | use OldTown\Workflow\Loader\WorkflowDescriptor; |
||
12 | use OldTown\Workflow\Loader\WorkflowFactoryInterface; |
||
13 | use OldTown\Workflow\Loader\XmlUtil; |
||
14 | use OldTown\Workflow\Util\Properties\Properties; |
||
15 | use OldTown\Workflow\Util\VariableResolverInterface; |
||
16 | use OldTown\Workflow\Spi\WorkflowStoreInterface; |
||
17 | use OldTown\Workflow\Exception\StoreException; |
||
18 | use Psr\Http\Message\UriInterface; |
||
19 | use OldTown\Workflow\Util\DefaultVariableResolver; |
||
20 | use DOMDocument; |
||
21 | use DOMElement; |
||
22 | |||
23 | /** |
||
24 | * Interface ConfigurationInterface |
||
25 | * |
||
26 | * @package OldTown\Workflow\Config |
||
27 | */ |
||
28 | class DefaultConfiguration implements ConfigurationInterface |
||
29 | { |
||
30 | /** |
||
31 | * @var DefaultConfiguration |
||
32 | */ |
||
33 | protected static $instance; |
||
34 | |||
35 | /** |
||
36 | * Пути по умолчнаию до файла с конфигом |
||
37 | * |
||
38 | * @var array |
||
39 | */ |
||
40 | protected static $defaultPathsToConfig = []; |
||
41 | |||
42 | /** |
||
43 | * Имя файла конфига по умолчанию |
||
44 | * |
||
45 | * @var string |
||
46 | */ |
||
47 | protected static $configFileName = 'osworkflow.xml'; |
||
48 | |||
49 | /** |
||
50 | * Флаг определяющий было ли иницилизированно workflow |
||
51 | * |
||
52 | * @var bool |
||
53 | */ |
||
54 | private $initialized = false; |
||
55 | |||
56 | /** |
||
57 | * @var VariableResolverInterface |
||
58 | */ |
||
59 | private $variableResolver; |
||
60 | |||
61 | /** |
||
62 | * Имя класса хранилища состояния workflow |
||
63 | * |
||
64 | * @var string |
||
65 | */ |
||
66 | private $persistenceClass; |
||
67 | |||
68 | /** |
||
69 | * Настройки хранилища |
||
70 | * |
||
71 | * @var array |
||
72 | */ |
||
73 | private $persistenceArgs = []; |
||
74 | |||
75 | /** |
||
76 | * @var WorkflowFactoryInterface |
||
77 | */ |
||
78 | private $factory; |
||
79 | |||
80 | /** |
||
81 | * Хранилище состояния workflow |
||
82 | * |
||
83 | * @var WorkflowStoreInterface |
||
84 | */ |
||
85 | private $store; |
||
86 | |||
87 | /** |
||
88 | * |
||
89 | */ |
||
90 | public function __construct() |
||
91 | { |
||
92 | $this->variableResolver = new DefaultVariableResolver(); |
||
93 | $this->factory = new UrlWorkflowFactory(); |
||
94 | $this->initDefaultPathsToConfig(); |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Иницализация путей по которым происходит поиск |
||
99 | * |
||
100 | * @return void |
||
101 | */ |
||
102 | protected function initDefaultPathsToConfig() |
||
103 | { |
||
104 | static::$defaultPathsToConfig[] = __DIR__ . '/../../config'; |
||
105 | } |
||
106 | |||
107 | /** |
||
108 | * @param string $workflowName |
||
109 | * @param object $layout |
||
110 | * @return void |
||
111 | */ |
||
112 | public function setLayout($workflowName, $layout) |
||
0 ignored issues
–
show
|
|||
113 | { |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * @param string $workflowName |
||
118 | * @return Object |
||
119 | */ |
||
120 | public function getLayout($workflowName) |
||
0 ignored issues
–
show
|
|||
121 | { |
||
122 | return null; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * @param string $name |
||
127 | * @return boolean |
||
128 | */ |
||
129 | public function isModifiable($name) |
||
130 | { |
||
131 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type declared by the interface OldTown\Workflow\Config\...Interface::isModifiable of type OldTown\Workflow\Config\true .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
132 | } |
||
133 | |||
134 | /** |
||
135 | * |
||
136 | * @return string |
||
137 | */ |
||
138 | public function getName() |
||
139 | { |
||
140 | return ''; |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * Возможность статически получать экземпляр конфигурации по умолчанию для workflow |
||
145 | * |
||
146 | * @return DefaultConfiguration |
||
147 | */ |
||
148 | public static function getInstance() |
||
149 | { |
||
150 | if (self::$instance instanceof self) { |
||
151 | return self::$instance; |
||
152 | } |
||
153 | |||
154 | self::$instance = new self(); |
||
155 | |||
156 | return self::$instance; |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Возвращает true, если фабрика инициализировала объект конфигурации |
||
161 | * |
||
162 | * @return boolean |
||
163 | */ |
||
164 | public function isInitialized() |
||
165 | { |
||
166 | return $this->initialized; |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Загружает указанный файл конфигурации |
||
171 | * |
||
172 | * @param UriInterface|null $url |
||
173 | * @return void |
||
174 | * @throws FactoryException |
||
175 | */ |
||
176 | public function load(UriInterface $url = null) |
||
177 | { |
||
178 | try { |
||
179 | $content = $this->getContentConfigFile($url); |
||
180 | |||
181 | libxml_use_internal_errors(true); |
||
182 | |||
183 | |||
184 | $xmlDoc = new DOMDocument(); |
||
185 | $resultLoadXml = $xmlDoc->loadXML($content); |
||
186 | |||
187 | View Code Duplication | if (!$resultLoadXml) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
188 | $error = libxml_get_last_error(); |
||
189 | if ($error instanceof \LibXMLError) { |
||
190 | $errMsg = "Error in workflow xml.\n"; |
||
191 | $errMsg .= "Message: {$error->message}.\n"; |
||
192 | $errMsg .= "File: {$error->file}.\n"; |
||
193 | $errMsg .= "Line: {$error->line}.\n"; |
||
194 | $errMsg .= "Column: {$error->column}."; |
||
195 | |||
196 | throw new InvalidParsingWorkflowException($errMsg); |
||
197 | } |
||
198 | } |
||
199 | /** @var DOMElement $root */ |
||
200 | $root = $xmlDoc->getElementsByTagName('osworkflow')->item(0); |
||
201 | |||
202 | |||
203 | $p = XmlUtil::getChildElement($root, 'persistence'); |
||
204 | $resolver = XmlUtil::getChildElement($root, 'resolver'); |
||
205 | $factoryElement = XmlUtil::getChildElement($root, 'factory'); |
||
206 | |||
207 | |||
208 | if (null !== $resolver && $resolver->hasAttribute('class')) { |
||
209 | $resolverClass = XmlUtil::getRequiredAttributeValue($resolver, 'class'); |
||
210 | |||
211 | if (!class_exists($resolverClass)) { |
||
212 | $errMsg = "Для variableResolver указан не существующий класс {$resolverClass}"; |
||
213 | throw new FactoryException($errMsg); |
||
214 | } |
||
215 | |||
216 | $variableResolver = new $resolverClass(); |
||
217 | if (!$variableResolver instanceof VariableResolverInterface) { |
||
218 | $errMsg = 'variableResolver должен реализовывать интерфейс VariableResolverInterface'; |
||
219 | throw new FactoryException($errMsg); |
||
220 | } |
||
221 | $this->variableResolver = $variableResolver; |
||
222 | } |
||
223 | |||
224 | $this->persistenceClass = XmlUtil::getRequiredAttributeValue($p, 'class'); |
||
0 ignored issues
–
show
It seems like
$p defined by \OldTown\Workflow\Loader...t($root, 'persistence') on line 203 can be null ; however, OldTown\Workflow\Loader\...equiredAttributeValue() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
225 | |||
226 | $args = XmlUtil::getChildElements($p, 'property'); |
||
0 ignored issues
–
show
It seems like
$p defined by \OldTown\Workflow\Loader...t($root, 'persistence') on line 203 can be null ; however, OldTown\Workflow\Loader\...til::getChildElements() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
227 | |||
228 | foreach ($args as $arg) { |
||
229 | $key = XmlUtil::getRequiredAttributeValue($arg, 'key'); |
||
230 | $value = XmlUtil::getRequiredAttributeValue($arg, 'value'); |
||
231 | $this->persistenceArgs[$key] = $value; |
||
232 | } |
||
233 | |||
234 | if (null !== $factoryElement) { |
||
235 | $class = null; |
||
236 | try { |
||
237 | $factoryClassName = XmlUtil::getRequiredAttributeValue($factoryElement, 'class'); |
||
238 | |||
239 | if (!class_exists($factoryClassName)) { |
||
240 | $errMsg = "Для фабрики workflow указан несуществующий класс {$factoryClassName}"; |
||
241 | throw new FactoryException($errMsg); |
||
242 | } |
||
243 | /** @var WorkflowFactoryInterface $factory */ |
||
244 | $factory = new $factoryClassName(); |
||
245 | |||
246 | if (!$factory instanceof WorkflowFactoryInterface) { |
||
247 | $errMsg = 'Фабрика должна реализовывать интерфейся WorkflowFactoryInterface'; |
||
248 | throw new FactoryException($errMsg); |
||
249 | } |
||
250 | |||
251 | $properties = new Properties(); |
||
252 | $props = XmlUtil::getChildElements($factoryElement, 'property'); |
||
253 | |||
254 | foreach ($props as $e) { |
||
255 | $key = XmlUtil::getRequiredAttributeValue($e, 'key'); |
||
256 | $value = XmlUtil::getRequiredAttributeValue($e, 'value'); |
||
257 | $properties->setProperty($key, $value); |
||
258 | } |
||
259 | |||
260 | $factory->init($properties); |
||
261 | $factory->initDone(); |
||
262 | |||
263 | $this->factory = $factory; |
||
264 | } catch (FactoryException $e) { |
||
265 | throw $e; |
||
266 | } catch (\Exception $e) { |
||
267 | $class = (string)$class; |
||
268 | $errMsg = "Ошибка создания фабрики workflow для класса {$class}"; |
||
269 | throw new FactoryException($errMsg, $e->getCode(), $e); |
||
270 | } |
||
271 | |||
272 | $this->initialized = true; |
||
273 | } |
||
274 | } catch (FactoryException $e) { |
||
275 | throw $e; |
||
276 | } catch (\Exception $e) { |
||
277 | $errMsg = 'Ошибка при работе с конфигом workflow'; |
||
278 | throw new FactoryException($errMsg, $e->getCode(), $e); |
||
279 | } |
||
280 | } |
||
281 | |||
282 | |||
283 | /** |
||
284 | * @param UriInterface $url |
||
285 | * |
||
286 | * @return string |
||
287 | * |
||
288 | * @throws FactoryException |
||
289 | */ |
||
290 | protected function getContentConfigFile(UriInterface $url = null) |
||
291 | { |
||
292 | if (null !== $url) { |
||
293 | $urlStr = (string)$url; |
||
294 | $content = file_get_contents($urlStr); |
||
295 | |||
296 | return $content; |
||
297 | } |
||
298 | |||
299 | $paths = static::getDefaultPathsToConfig(); |
||
300 | |||
301 | $content = null; |
||
302 | foreach ($paths as $path) { |
||
303 | $path = realpath($path); |
||
304 | if ($path) { |
||
305 | $filePath = $path . DIRECTORY_SEPARATOR . static::getConfigFileName(); |
||
306 | if (file_exists($filePath)) { |
||
307 | $content = file_get_contents($filePath); |
||
308 | break; |
||
309 | } |
||
310 | } |
||
311 | } |
||
312 | |||
313 | if (null === $content) { |
||
314 | $errMsg = 'Не удалось прочитать конфигурационный файл'; |
||
315 | throw new FactoryException($errMsg); |
||
316 | } |
||
317 | |||
318 | return $content; |
||
319 | } |
||
320 | |||
321 | /** |
||
322 | * @return array |
||
323 | */ |
||
324 | public static function getDefaultPathsToConfig() |
||
325 | { |
||
326 | return self::$defaultPathsToConfig; |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * @param array $defaultPathsToConfig |
||
331 | */ |
||
332 | public static function setDefaultPathsToConfig(array $defaultPathsToConfig = []) |
||
333 | { |
||
334 | self::$defaultPathsToConfig = $defaultPathsToConfig; |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * @param string $path |
||
339 | */ |
||
340 | public static function addDefaultPathToConfig($path) |
||
341 | { |
||
342 | $path = (string)$path; |
||
343 | |||
344 | array_unshift(self::$defaultPathsToConfig, $path); |
||
345 | } |
||
346 | |||
347 | |||
348 | /** |
||
349 | * @return string |
||
350 | */ |
||
351 | public static function getConfigFileName() |
||
352 | { |
||
353 | return self::$configFileName; |
||
354 | } |
||
355 | |||
356 | /** |
||
357 | * @param string $configFileName |
||
358 | */ |
||
359 | public static function setConfigFileName($configFileName) |
||
360 | { |
||
361 | self::$configFileName = $configFileName; |
||
362 | } |
||
363 | |||
364 | |||
365 | /** |
||
366 | * Возвращает resolver для работы с переменными |
||
367 | * |
||
368 | * @return VariableResolverInterface|DefaultVariableResolver |
||
369 | */ |
||
370 | public function getVariableResolver() |
||
371 | { |
||
372 | return $this->variableResolver; |
||
373 | } |
||
374 | |||
375 | |||
376 | /** |
||
377 | * Удаляет workflow |
||
378 | * |
||
379 | * @param string $workflow имя удаляемого workflow |
||
380 | * @return boolean в случае успешного удаления возвращает true, в противном случае false |
||
381 | * @throws FactoryException |
||
382 | */ |
||
383 | public function removeWorkflow($workflow) |
||
384 | { |
||
385 | $this->getFactory()->removeWorkflow($workflow); |
||
386 | } |
||
387 | |||
388 | /** |
||
389 | * Сохраняет Workflow |
||
390 | * @param string $name имя сохраняемого workflow |
||
391 | * @param WorkflowDescriptor $descriptor дескриптор workflow |
||
392 | * @param boolean $replace - флаг определяющий, можно ли замениить workflow |
||
393 | * |
||
394 | * @return boolean |
||
395 | * |
||
396 | * @throws FactoryException |
||
397 | * @throws \OldTown\Workflow\Exception\InvalidWorkflowDescriptorException |
||
398 | * |
||
399 | */ |
||
400 | public function saveWorkflow($name, WorkflowDescriptor $descriptor, $replace = false) |
||
401 | { |
||
402 | $this->getFactory()->saveWorkflow($name, $descriptor, $replace); |
||
403 | } |
||
404 | |||
405 | /** |
||
406 | * @return WorkflowFactoryInterface |
||
407 | */ |
||
408 | public function getFactory() |
||
409 | { |
||
410 | return $this->factory; |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * Возвращает имя класса описвающего хранилидище, в котором сохраняется workflow |
||
415 | * |
||
416 | * @return string |
||
417 | */ |
||
418 | public function getPersistence() |
||
419 | { |
||
420 | return $this->persistenceClass; |
||
421 | } |
||
422 | |||
423 | /** |
||
424 | * Получить аргументы хранилища |
||
425 | * |
||
426 | * @return array |
||
427 | */ |
||
428 | public function getPersistenceArgs() |
||
429 | { |
||
430 | return $this->persistenceArgs; |
||
431 | } |
||
432 | |||
433 | |||
434 | /** |
||
435 | * Возвращает имя дескриптора workflow |
||
436 | * |
||
437 | * @param string $name имя workflow |
||
438 | * @throws FactoryException |
||
439 | * @return WorkflowDescriptor |
||
440 | */ |
||
441 | public function getWorkflow($name) |
||
442 | { |
||
443 | $workflow = $this->getFactory()->getWorkflow($name); |
||
444 | |||
445 | if (!$workflow instanceof WorkflowDescriptor) { |
||
446 | throw new FactoryException('Unknown workflow name'); |
||
447 | } |
||
448 | |||
449 | return $workflow; |
||
450 | } |
||
451 | |||
452 | /** |
||
453 | * Получает список имен всех доступных workflow |
||
454 | * @throws FactoryException |
||
455 | * @return String[] |
||
456 | */ |
||
457 | public function getWorkflowNames() |
||
458 | { |
||
459 | $names = $this->getFactory()->getWorkflowNames(); |
||
460 | |||
461 | return $names; |
||
462 | } |
||
463 | |||
464 | /** |
||
465 | * Получает хранилище Workflow |
||
466 | * |
||
467 | * @return WorkflowStoreInterface |
||
468 | * @throws StoreException |
||
469 | * @throws \OldTown\Workflow\Exception\FactoryException |
||
470 | */ |
||
471 | public function getWorkflowStore() |
||
472 | { |
||
473 | if (!$this->store) { |
||
474 | $class = $this->getPersistence(); |
||
475 | |||
476 | if (!class_exists($class)) { |
||
477 | $errMsg = sprintf( |
||
478 | 'Отсутствует класс хранилища %s', |
||
479 | $class |
||
480 | ); |
||
481 | throw new FactoryException($errMsg); |
||
482 | } |
||
483 | |||
484 | |||
485 | $store = new $class(); |
||
486 | if (!$store instanceof WorkflowStoreInterface) { |
||
487 | throw new FactoryException('Ошибка при создание хранилища'); |
||
488 | } |
||
489 | |||
490 | $storeArgs = $this->getPersistenceArgs(); |
||
491 | $store->init($storeArgs); |
||
492 | |||
493 | $this->store = $store; |
||
494 | } |
||
495 | |||
496 | return $this->store; |
||
497 | } |
||
498 | } |
||
499 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.