netresearch /
kite
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\Workflow |
||
| 9 | * @author Christian Opitz <[email protected]> |
||
| 10 | * @license http://www.netresearch.de Netresearch Copyright |
||
| 11 | * @link http://www.netresearch.de |
||
| 12 | */ |
||
| 13 | |||
| 14 | namespace Netresearch\Kite\Workflow; |
||
| 15 | use Netresearch\Kite\Exception; |
||
| 16 | use Netresearch\Kite\Service\Descriptor; |
||
| 17 | use Netresearch\Kite\Task; |
||
| 18 | use Netresearch\Kite\Workflow; |
||
| 19 | |||
| 20 | /** |
||
| 21 | * Renders the Task and Workflows reference |
||
| 22 | * |
||
| 23 | * @internal Used to render the kite reference |
||
| 24 | * @category Netresearch |
||
| 25 | * @package Netresearch\Kite\Workflow |
||
| 26 | * @author Christian Opitz <[email protected]> |
||
| 27 | * @license http://www.netresearch.de Netresearch Copyright |
||
| 28 | * @link http://www.netresearch.de |
||
| 29 | */ |
||
| 30 | class RenderReference extends Workflow |
||
| 31 | { |
||
| 32 | /** |
||
| 33 | * @var \Composer\Autoload\ClassLoader[] |
||
| 34 | */ |
||
| 35 | protected $loaders = []; |
||
| 36 | |||
| 37 | /** |
||
| 38 | * Configure variables |
||
| 39 | * |
||
| 40 | * @return array |
||
| 41 | */ |
||
| 42 | protected function configureVariables() |
||
| 43 | { |
||
| 44 | return [ |
||
| 45 | 'file' => [ |
||
| 46 | 'type' => 'string', |
||
| 47 | 'option' => true, |
||
| 48 | 'shortcut' => 'f', |
||
| 49 | 'required' => true, |
||
| 50 | 'label' => 'File to write to' |
||
| 51 | ] |
||
| 52 | ] + parent::configureVariables(); |
||
| 53 | } |
||
| 54 | |||
| 55 | /** |
||
| 56 | * Assemble the task |
||
| 57 | * |
||
| 58 | * @return void |
||
| 59 | */ |
||
| 60 | public function assemble() |
||
| 61 | { |
||
| 62 | $this->callback( |
||
| 63 | function () { |
||
| 64 | $this->findLoaders(); |
||
| 65 | $file = $this->get('file'); |
||
| 66 | $this->console->getFilesystem()->ensureDirectoryExists(dirname($file)); |
||
| 67 | file_put_contents($file, $this->render()); |
||
| 68 | } |
||
| 69 | ); |
||
| 70 | } |
||
| 71 | |||
| 72 | /** |
||
| 73 | * Render the reference |
||
| 74 | * |
||
| 75 | * @return string |
||
| 76 | */ |
||
| 77 | public function render() |
||
| 78 | { |
||
| 79 | $descriptor = new Descriptor(); |
||
| 80 | $lines = [ |
||
| 81 | '.. header::', |
||
| 82 | '', |
||
| 83 | ' .. image:: ../res/logo/logo.png', |
||
| 84 | ' :width: 200 px', |
||
| 85 | ' :alt: Kite', |
||
| 86 | '', |
||
| 87 | '****************************', |
||
| 88 | 'Kite: Make your projects fly', |
||
| 89 | '****************************', |
||
| 90 | '', |
||
| 91 | '===========================', |
||
| 92 | 'Task and Workflow reference', |
||
| 93 | '===========================', |
||
| 94 | '', |
||
| 95 | '.. sidebar:: Navigation', |
||
| 96 | '', |
||
| 97 | ' `Back to manual <../README.rst>`_', |
||
| 98 | '', |
||
| 99 | ' .. contents::', |
||
| 100 | ' :depth: 2', |
||
| 101 | '' |
||
| 102 | ]; |
||
| 103 | $commonVars = $this->getCommonVariables(); |
||
| 104 | $lines[] = 'Common options'; |
||
| 105 | $lines[] = '=============='; |
||
| 106 | $lines[] = 'The following options are available on the most tasks and workflows (unless they deactivated them):'; |
||
| 107 | $lines[] = ''; |
||
| 108 | $this->renderVariables($lines, $commonVars, 'common'); |
||
| 109 | |||
| 110 | foreach (['task', 'workflow'] as $type) { |
||
| 111 | $lines[] = ''; |
||
| 112 | $lines[] = ucfirst($type) . 's'; |
||
| 113 | $lines[] = str_repeat('=', strlen($type) + 1); |
||
| 114 | $lines[] = ''; |
||
| 115 | $taskObjects = $this->loadTaskObjects($type); |
||
| 116 | foreach ($taskObjects as $name => $taskObject) { |
||
| 117 | if ($taskObject instanceof self) { |
||
| 118 | continue; |
||
| 119 | } |
||
| 120 | $lines[] = ''; |
||
| 121 | $lines[] = $name; |
||
| 122 | $lines[] = str_repeat('-', strlen($name)); |
||
| 123 | $lines[] = ''; |
||
| 124 | $lines[] = str_replace("\n", "\n\n", $descriptor->describeTask($taskObject)); |
||
| 125 | $lines[] = ''; |
||
| 126 | $variableConfig = $taskObject->get('_variableConfiguration'); |
||
| 127 | $taskVariables = []; |
||
| 128 | $taskCommonVariables = []; |
||
| 129 | foreach ($variableConfig as $configName => $config) { |
||
| 130 | if (is_array($config)) { |
||
| 131 | if (array_key_exists($configName, $commonVars) && $commonVars[$configName] === $config) { |
||
| 132 | $taskCommonVariables[] = $configName; |
||
| 133 | } else { |
||
| 134 | $taskVariables[$configName] = $config; |
||
| 135 | } |
||
| 136 | } |
||
| 137 | } |
||
| 138 | if ($taskVariables) { |
||
|
0 ignored issues
–
show
|
|||
| 139 | $lines[] = 'Options'; |
||
| 140 | $lines[] = '```````'; |
||
| 141 | $lines[] = ''; |
||
| 142 | $this->renderVariables($lines, $taskVariables, $type . '-' . $name); |
||
| 143 | } |
||
| 144 | if ($taskCommonVariables) { |
||
|
0 ignored issues
–
show
The expression
$taskCommonVariables of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||
| 145 | $lines[] = 'Common options'; |
||
| 146 | $lines[] = '``````````````'; |
||
| 147 | $links = []; |
||
| 148 | foreach ($taskCommonVariables as $configName) { |
||
| 149 | $links[] = "|common-$configName|_"; |
||
| 150 | } |
||
| 151 | $lines[] = implode(', ', $links); |
||
| 152 | $lines[] = ''; |
||
| 153 | } |
||
| 154 | } |
||
| 155 | } |
||
| 156 | |||
| 157 | return implode("\n", $lines); |
||
| 158 | } |
||
| 159 | |||
| 160 | /** |
||
| 161 | * Render the variables |
||
| 162 | * |
||
| 163 | * @param array $lines The lines |
||
| 164 | * @param array $variables The variables |
||
| 165 | * @param string $anchorPrefix The anchor prefix |
||
| 166 | * |
||
| 167 | * @return void |
||
| 168 | */ |
||
| 169 | protected function renderVariables(&$lines, $variables, $anchorPrefix) |
||
| 170 | { |
||
| 171 | $lines[] = '.. list-table::'; |
||
| 172 | $lines[] = ' :header-rows: 1'; |
||
| 173 | $lines[] = ' :widths: 5 5 5 5 80'; |
||
| 174 | $lines[] = ''; |
||
| 175 | $keys = ['type', 'default', 'required', 'label']; |
||
| 176 | $lines[] = ' * - Name'; |
||
| 177 | foreach ($keys as $key) { |
||
| 178 | $lines[] = ' - ' . ucfirst($key); |
||
| 179 | } |
||
| 180 | |||
| 181 | foreach ($variables as $configName => $config) { |
||
| 182 | if (!is_array($config)) { |
||
| 183 | continue; |
||
| 184 | } |
||
| 185 | $lines[] = ' * - '; |
||
| 186 | $lines[] = ''; |
||
| 187 | $lines[] = ' .. |' . $anchorPrefix . '-' . $configName . '| replace:: ' . $configName; |
||
| 188 | $lines[] = ''; |
||
| 189 | $lines[] = ' .. _' . $anchorPrefix . '-' . $configName . ':'; |
||
| 190 | $lines[] = ''; |
||
| 191 | $lines[] = ' ' . $configName; |
||
| 192 | $lines[] = ''; |
||
| 193 | foreach ($keys as $key) { |
||
| 194 | if (!array_key_exists($key, $config)) { |
||
| 195 | $value = '\\-'; |
||
| 196 | } elseif ($key === 'default') { |
||
| 197 | $v = $config[$key]; |
||
| 198 | $value = $v === null ? 'null' : ($v === true ? 'true' : ($v === false ? 'false' : $v)); |
||
| 199 | if (is_string($value)) { |
||
| 200 | $value = ':code:`' . $value . '`'; |
||
| 201 | } |
||
| 202 | } elseif ($key === 'required') { |
||
| 203 | $value = $config[$key] === true ? 'X' : $config[$key]; |
||
| 204 | } else { |
||
| 205 | $value = $config[$key]; |
||
| 206 | } |
||
| 207 | if (is_array($value)) { |
||
| 208 | $value = "\n\n .. code::php\n\n " . str_replace("\n", "\n\n ", call_user_func('print' . '_r', $value, true)) . "\n\n"; |
||
| 209 | } else { |
||
| 210 | $value = str_replace("\n", "\n\n ", $value); |
||
| 211 | } |
||
| 212 | $value = preg_replace('/\{@see\s+(' . implode('|', array_keys($variables)) . ')\}/', '|' . $anchorPrefix . '-$1|_', $value); |
||
| 213 | $lines[] = ' - ' . $value; |
||
| 214 | } |
||
| 215 | } |
||
| 216 | $lines[] = ''; |
||
| 217 | } |
||
| 218 | |||
| 219 | /** |
||
| 220 | * Get the common variables |
||
| 221 | * |
||
| 222 | * @return mixed |
||
| 223 | */ |
||
| 224 | protected function getCommonVariables() |
||
| 225 | { |
||
| 226 | static $commonVars; |
||
| 227 | if (!is_array($commonVars)) { |
||
| 228 | $className = 'NetresearchKiteTask' . uniqid(); |
||
| 229 | eval('class ' . $className . ' extends \\Netresearch\\Kite\\Task {}'); |
||
|
0 ignored issues
–
show
It is generally not recommended to use
eval unless absolutely required.
On one hand, Loading history...
|
|||
| 230 | $instance = new $className($this); |
||
| 231 | $commonVars = $instance->get('_variableConfiguration'); |
||
| 232 | } |
||
| 233 | return $commonVars; |
||
| 234 | } |
||
| 235 | |||
| 236 | /** |
||
| 237 | * Load task objects |
||
| 238 | * |
||
| 239 | * @param string $type workflow or task |
||
| 240 | * |
||
| 241 | * @return Task[] |
||
| 242 | */ |
||
| 243 | protected function loadTaskObjects($type) |
||
| 244 | { |
||
| 245 | $objects = []; |
||
| 246 | $requiredType = 'Netresearch\\Kite\\' . ucfirst($type); |
||
| 247 | foreach ($this->factory->getNamespaces($type) as $namespace) { |
||
| 248 | $namespaceLength = strlen($namespace); |
||
| 249 | if ($dir = $this->findDirectoryForNamespace($namespace)) { |
||
| 250 | foreach ($this->loadFilesInDirectory($dir) as $file) { |
||
| 251 | if (substr($file, -4) !== '.php') { |
||
| 252 | continue; |
||
| 253 | } |
||
| 254 | $class = $namespace . '\\' . substr(strtr($file, '/', '\\'), 0, -4); |
||
| 255 | $reflectionClass = new \ReflectionClass($class); |
||
| 256 | if (!$reflectionClass->isSubclassOf($requiredType) || !$reflectionClass->isInstantiable()) { |
||
| 257 | continue; |
||
| 258 | } |
||
| 259 | $namePart = substr($reflectionClass->getName(), $namespaceLength + 1); |
||
| 260 | $parts = []; |
||
| 261 | foreach (explode('\\', $namePart) as $part) { |
||
| 262 | $parts[] = lcfirst($part); |
||
| 263 | } |
||
| 264 | $name = implode('-', $parts); |
||
| 265 | if ($type === 'task') { |
||
| 266 | $name = substr($name, 0, -4); |
||
| 267 | } |
||
| 268 | if (!array_key_exists($name, $objects)) { |
||
| 269 | $objects[$name] = new $class($this); |
||
| 270 | } |
||
| 271 | } |
||
| 272 | } else { |
||
| 273 | $this->output("<error>No {$type}s found in namespace $namespace</error>"); |
||
| 274 | } |
||
| 275 | } |
||
| 276 | ksort($objects); |
||
| 277 | return $objects; |
||
| 278 | } |
||
| 279 | |||
| 280 | /** |
||
| 281 | * Find the loaders |
||
| 282 | * |
||
| 283 | * @return void |
||
| 284 | */ |
||
| 285 | protected function findLoaders() |
||
| 286 | { |
||
| 287 | $autoloadFunctions = spl_autoload_functions(); |
||
| 288 | if (!is_array($autoloadFunctions)) { |
||
| 289 | throw new Exception('No autoloaders registered'); |
||
| 290 | } |
||
| 291 | foreach ($autoloadFunctions as $autoloadFunction) { |
||
| 292 | if (!is_array($autoloadFunction) || !$autoloadFunction[0] instanceof \Composer\Autoload\ClassLoader) { |
||
|
0 ignored issues
–
show
The class
Composer\Autoload\ClassLoader does not exist. Did you forget a USE statement, or did you not list all dependencies?
This error could be the result of: 1. Missing dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed. Loading history...
|
|||
| 293 | throw new Exception('Can only work with composer autoloaders'); |
||
| 294 | } |
||
| 295 | $this->loaders[] = $autoloadFunction[0]; |
||
| 296 | } |
||
| 297 | } |
||
| 298 | |||
| 299 | /** |
||
| 300 | * Get the files within a directory |
||
| 301 | * |
||
| 302 | * @param string $dir The directory |
||
| 303 | * |
||
| 304 | * @return array |
||
| 305 | */ |
||
| 306 | private function loadFilesInDirectory($dir) |
||
| 307 | { |
||
| 308 | $iterator = new \RecursiveIteratorIterator( |
||
| 309 | new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS) |
||
| 310 | ); |
||
| 311 | $files = []; |
||
| 312 | foreach ($iterator as $item) { |
||
| 313 | /** @var \SplFileInfo $item */ |
||
| 314 | if ($item->isFile()) { |
||
| 315 | // Add a new element to the array of the current file name. |
||
| 316 | $files[] = $iterator->getSubPathName(); |
||
| 317 | } |
||
| 318 | } |
||
| 319 | return $files; |
||
| 320 | } |
||
| 321 | |||
| 322 | /** |
||
| 323 | * Find the base directory of a namespace |
||
| 324 | * |
||
| 325 | * @param string $namespace The namespace |
||
| 326 | * |
||
| 327 | * @return string |
||
| 328 | */ |
||
| 329 | private function findDirectoryForNamespace($namespace) |
||
| 330 | { |
||
| 331 | foreach ($this->loaders as $loader) { |
||
| 332 | // PSR-4 lookup |
||
| 333 | $logicalPathPsr4 = trim(strtr($namespace, '\\', DIRECTORY_SEPARATOR), DIRECTORY_SEPARATOR); |
||
| 334 | |||
| 335 | foreach ($loader->getPrefixesPsr4() as $prefix => $dirs) { |
||
| 336 | $length = strlen($prefix); |
||
| 337 | if (substr($namespace, 0, $length) !== $prefix) { |
||
| 338 | continue; |
||
| 339 | } |
||
| 340 | foreach ($dirs as $dir) { |
||
| 341 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { |
||
| 342 | return $file; |
||
| 343 | } |
||
| 344 | } |
||
| 345 | } |
||
| 346 | |||
| 347 | // PSR-4 fallback dirs |
||
| 348 | foreach ($loader->getFallbackDirsPsr4() as $dir) { |
||
| 349 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { |
||
| 350 | return $file; |
||
| 351 | } |
||
| 352 | } |
||
| 353 | |||
| 354 | // PSR-0 lookup |
||
| 355 | if (false !== $pos = strrpos($namespace, '\\')) { |
||
| 356 | // namespaced class name |
||
| 357 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) |
||
| 358 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); |
||
| 359 | } else { |
||
| 360 | // PEAR-like class name |
||
| 361 | $logicalPathPsr0 = strtr($namespace, '_', DIRECTORY_SEPARATOR); |
||
| 362 | } |
||
| 363 | |||
| 364 | foreach ($loader->getPrefixes() as $prefix => $dirs) { |
||
| 365 | if (0 === strpos($namespace, $prefix)) { |
||
| 366 | foreach ($dirs as $dir) { |
||
| 367 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { |
||
| 368 | return $file; |
||
| 369 | } |
||
| 370 | } |
||
| 371 | } |
||
| 372 | } |
||
| 373 | |||
| 374 | // PSR-0 fallback dirs |
||
| 375 | foreach ($loader->getFallbackDirs() as $dir) { |
||
| 376 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { |
||
| 377 | return $file; |
||
| 378 | } |
||
| 379 | } |
||
| 380 | |||
| 381 | // PSR-0 include paths. |
||
| 382 | if ($file = stream_resolve_include_path($logicalPathPsr0)) { |
||
| 383 | return $file; |
||
| 384 | } |
||
| 385 | } |
||
| 386 | } |
||
| 387 | } |
||
| 388 | |||
| 389 | ?> |
||
| 390 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.