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 | * For the full copyright and license information, please view the LICENSE.md |
||
4 | * file that was distributed with this source code. |
||
5 | */ |
||
6 | |||
7 | namespace Notamedia\ConsoleJedi\Application; |
||
8 | |||
9 | use Bitrix\Main\DB\ConnectionException; |
||
10 | use Bitrix\Main\Loader; |
||
11 | use Bitrix\Main\ModuleManager; |
||
12 | use Notamedia\ConsoleJedi\Agent\Command\OnCronCommand; |
||
13 | use Notamedia\ConsoleJedi\Agent\Command\ExecuteCommand; |
||
14 | use Notamedia\ConsoleJedi\Application\Exception\ConfigurationException; |
||
15 | use Notamedia\ConsoleJedi\Cache\Command\ClearCommand; |
||
16 | use Notamedia\ConsoleJedi\Environment\Command\InitCommand; |
||
17 | use Notamedia\ConsoleJedi\Module\Command as Module; |
||
18 | use Notamedia\ConsoleJedi\Search\Command\ReIndexCommand; |
||
19 | use Notamedia\ConsoleJedi\Iblock\Command\ExportCommand; |
||
20 | use Notamedia\ConsoleJedi\Iblock\Command\ImportCommand; |
||
21 | use Symfony\Component\Console\Command\Command; |
||
22 | use Symfony\Component\Console\Input\InputInterface; |
||
23 | use Symfony\Component\Console\Output\OutputInterface; |
||
24 | use Symfony\Component\Filesystem\Filesystem; |
||
25 | |||
26 | /** |
||
27 | * Console Jedi application. |
||
28 | * |
||
29 | * @author Nik Samokhvalov <[email protected]> |
||
30 | */ |
||
31 | class Application extends \Symfony\Component\Console\Application |
||
32 | { |
||
33 | /** |
||
34 | * Version of the Console Jedi application. |
||
35 | */ |
||
36 | const VERSION = '1.0.0'; |
||
37 | /** |
||
38 | * Default name of configuration file. |
||
39 | */ |
||
40 | const CONFIG_DEFAULT_FILE = './.jedi.php'; |
||
41 | /** |
||
42 | * Bitrix is unavailable. |
||
43 | */ |
||
44 | const BITRIX_STATUS_UNAVAILABLE = 500; |
||
45 | /** |
||
46 | * Bitrix is available, but not have connection to DB. |
||
47 | */ |
||
48 | const BITRIX_STATUS_NO_DB_CONNECTION = 100; |
||
49 | /** |
||
50 | * Bitrix is available. |
||
51 | */ |
||
52 | const BITRIX_STATUS_COMPLETE = 0; |
||
53 | /** |
||
54 | * @var int Status of Bitrix kernel. Value of constant `Application::BITRIX_STATUS_*`. |
||
55 | */ |
||
56 | protected $bitrixStatus = Application::BITRIX_STATUS_UNAVAILABLE; |
||
57 | /** |
||
58 | * @var null|string |
||
59 | */ |
||
60 | private $documentRoot = null; |
||
61 | /** |
||
62 | * @var null|array |
||
63 | */ |
||
64 | private $configuration = null; |
||
65 | |||
66 | /** |
||
67 | * {@inheritdoc} |
||
68 | */ |
||
69 | public function __construct($name = 'Console Jedi', $version = self::VERSION) |
||
70 | { |
||
71 | parent::__construct($name, static::VERSION); |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * {@inheritdoc} |
||
76 | */ |
||
77 | public function doRun(InputInterface $input, OutputInterface $output) |
||
78 | { |
||
79 | if ($this->getConfiguration() === null) { |
||
80 | $this->loadConfiguration(); |
||
81 | } |
||
82 | |||
83 | if (!in_array($this->getCommandName($input), ['environment:init', 'env:init'])) { |
||
84 | $this->initializeBitrix(); |
||
85 | } |
||
86 | |||
87 | if ($this->getConfiguration()) { |
||
88 | foreach ($this->getBitrixCommands() as $bitrixCommand) { |
||
89 | $this->add($bitrixCommand); |
||
90 | } |
||
91 | |||
92 | foreach ($this->getConfiguration()['commands'] as $command) { |
||
93 | $this->add($command); |
||
94 | } |
||
95 | } |
||
96 | |||
97 | if ($this->isBitrixLoaded() && $this->getConfiguration()['useModules'] === true) { |
||
98 | foreach ($this->getModulesCommands() as $moduleCommand) { |
||
99 | $this->add($moduleCommand); |
||
100 | } |
||
101 | } |
||
102 | |||
103 | $exitCode = parent::doRun($input, $output); |
||
104 | |||
105 | if ($this->getConfiguration() === null) { |
||
106 | $output->writeln(PHP_EOL . '<error>No configuration loaded.</error> ' |
||
107 | . 'Please run <info>init</info> command first'); |
||
108 | } else { |
||
109 | switch ($this->getBitrixStatus()) { |
||
110 | case static::BITRIX_STATUS_UNAVAILABLE: |
||
111 | $output->writeln(PHP_EOL . sprintf('<error>No Bitrix kernel found in %s.</error> ' |
||
112 | . 'Please run <info>env:init</info> command to configure', $this->getDocumentRoot())); |
||
113 | break; |
||
114 | |||
115 | case static::BITRIX_STATUS_NO_DB_CONNECTION: |
||
116 | $output->writeln(PHP_EOL . '<error>Bitrix database connection is unavailable.</error>'); |
||
117 | break; |
||
118 | |||
119 | case static::BITRIX_STATUS_COMPLETE: |
||
120 | if ($this->getCommandName($input) === null) { |
||
121 | $output->writeln(PHP_EOL . sprintf('Using Bitrix <info>kernel v%s</info>.</info>', SM_VERSION), |
||
122 | OutputInterface::VERBOSITY_VERY_VERBOSE); |
||
123 | } |
||
124 | break; |
||
125 | } |
||
126 | } |
||
127 | |||
128 | return $exitCode; |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * {@inheritdoc} |
||
133 | */ |
||
134 | protected function getDefaultCommands() |
||
135 | { |
||
136 | $commands = parent::getDefaultCommands(); |
||
137 | $commands[] = new \Notamedia\ConsoleJedi\Application\Command\InitCommand(); |
||
138 | |||
139 | return $commands; |
||
0 ignored issues
–
show
|
|||
140 | } |
||
141 | |||
142 | /** |
||
143 | * Gets Bitrix console commands from this package. |
||
144 | * |
||
145 | * @return Command[] |
||
146 | */ |
||
147 | protected function getBitrixCommands() |
||
148 | { |
||
149 | return array_merge( |
||
150 | [ |
||
151 | new OnCronCommand(), |
||
152 | new ExecuteCommand(), |
||
153 | new ClearCommand(), |
||
154 | new InitCommand(), |
||
155 | new ReIndexCommand(), |
||
156 | new ExportCommand(), |
||
157 | new ImportCommand(), |
||
158 | new ReIndexCommand(), |
||
159 | ], |
||
160 | Module\ModuleCommand::getCommands() |
||
161 | ); |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Gets console commands from modules. |
||
166 | * |
||
167 | * @return Command[] |
||
168 | * |
||
169 | * @throws \Bitrix\Main\LoaderException |
||
170 | */ |
||
171 | protected function getModulesCommands() |
||
172 | { |
||
173 | $commands = []; |
||
174 | |||
175 | foreach (ModuleManager::getInstalledModules() as $module) { |
||
176 | $cliFile = getLocalPath('modules/' . $module['ID'] . '/cli.php'); |
||
177 | |||
178 | if ($cliFile === false) { |
||
179 | continue; |
||
180 | } elseif (!Loader::includeModule($module['ID'])) { |
||
181 | continue; |
||
182 | } |
||
183 | |||
184 | $config = include_once $this->getDocumentRoot() . $cliFile; |
||
185 | |||
186 | if (isset($config['commands']) && is_array($config['commands'])) { |
||
187 | $commands = array_merge($commands, $config['commands']); |
||
188 | } |
||
189 | } |
||
190 | |||
191 | return $commands; |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Loading application configuration. |
||
196 | * |
||
197 | * @param string $path Path to configuration file. |
||
198 | * |
||
199 | * @return bool |
||
200 | * |
||
201 | * @throws ConfigurationException |
||
202 | */ |
||
203 | public function loadConfiguration($path = self::CONFIG_DEFAULT_FILE) |
||
0 ignored issues
–
show
loadConfiguration uses the super-global variable $_SERVER which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
204 | { |
||
205 | if (!is_file($path)) { |
||
206 | return false; |
||
207 | } |
||
208 | |||
209 | $this->configuration = include $path; |
||
210 | |||
211 | if (!is_array($this->configuration)) { |
||
212 | throw new ConfigurationException('Configuration file ' . $path . ' must return an array'); |
||
213 | } |
||
214 | |||
215 | $filesystem = new Filesystem(); |
||
216 | |||
217 | if ($filesystem->isAbsolutePath($this->configuration['web-dir'])) { |
||
218 | $this->setDocumentRoot($this->configuration['web-dir']); |
||
219 | } else { |
||
220 | $this->setDocumentRoot($this->getRoot() . '/' . $this->configuration['web-dir']); |
||
221 | } |
||
222 | |||
223 | if (!is_dir($_SERVER['DOCUMENT_ROOT'])) { |
||
224 | return false; |
||
225 | } |
||
226 | |||
227 | return true; |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * Gets application configuration. |
||
232 | * |
||
233 | * @return null|array |
||
234 | */ |
||
235 | public function getConfiguration() |
||
236 | { |
||
237 | return $this->configuration; |
||
238 | } |
||
239 | |||
240 | /** |
||
241 | * Initialize kernel of Bitrix. |
||
242 | * |
||
243 | * @return int The status of readiness kernel. |
||
244 | */ |
||
245 | public function initializeBitrix() |
||
0 ignored issues
–
show
initializeBitrix uses the super-global variable $_SERVER which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
246 | { |
||
247 | if ($this->bitrixStatus === static::BITRIX_STATUS_COMPLETE) { |
||
248 | return static::BITRIX_STATUS_COMPLETE; |
||
249 | } elseif (!$this->checkBitrix()) { |
||
250 | return static::BITRIX_STATUS_UNAVAILABLE; |
||
251 | } |
||
252 | |||
253 | define('NO_KEEP_STATISTIC', true); |
||
254 | define('NOT_CHECK_PERMISSIONS', true); |
||
255 | |||
256 | try { |
||
257 | /** |
||
258 | * Declare global legacy variables |
||
259 | * |
||
260 | * Including kernel here makes them local by default but some modules depend on them in installation class |
||
261 | */ |
||
262 | global |
||
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
![]() |
|||
263 | /** @noinspection PhpUnusedLocalVariableInspection */ |
||
264 | $DB, $DBType, $DBHost, $DBLogin, $DBPassword, $DBName, $DBDebug, $DBDebugToFile, $APPLICATION, $USER, $DBSQLServerType; |
||
265 | |||
266 | require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php'; |
||
267 | |||
268 | if (defined('B_PROLOG_INCLUDED') && B_PROLOG_INCLUDED === true) { |
||
269 | $this->bitrixStatus = static::BITRIX_STATUS_COMPLETE; |
||
270 | } |
||
271 | } catch (ConnectionException $e) { |
||
0 ignored issues
–
show
The class
Bitrix\Main\DB\ConnectionException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis. ![]() |
|||
272 | $this->bitrixStatus = static::BITRIX_STATUS_NO_DB_CONNECTION; |
||
273 | } |
||
274 | |||
275 | return $this->bitrixStatus; |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Checks readiness of Bitrix for kernel initialize. |
||
280 | * |
||
281 | * @return bool |
||
282 | */ |
||
283 | public function checkBitrix() |
||
0 ignored issues
–
show
checkBitrix uses the super-global variable $_SERVER which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
284 | { |
||
285 | if ( |
||
286 | !is_file($_SERVER['DOCUMENT_ROOT'] . '/bitrix/.settings.php') |
||
287 | && !is_file($_SERVER['DOCUMENT_ROOT'] . '/bitrix/.settings_extra.php') |
||
288 | ) { |
||
289 | return false; |
||
290 | } |
||
291 | |||
292 | return true; |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * Gets Bitrix status. |
||
297 | * |
||
298 | * @return int Value of constant `Application::BITRIX_STATUS_*`. |
||
299 | */ |
||
300 | public function getBitrixStatus() |
||
301 | { |
||
302 | return $this->bitrixStatus; |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * Checks that the Bitrix kernel is loaded. |
||
307 | * |
||
308 | * @return bool |
||
309 | */ |
||
310 | public function isBitrixLoaded() |
||
311 | { |
||
312 | return $this->bitrixStatus === static::BITRIX_STATUS_COMPLETE; |
||
313 | } |
||
314 | |||
315 | /** |
||
316 | * Autoloader classes of the tests. |
||
317 | * |
||
318 | * Initializes Bitrix kernel, finds and connects files in directory `vendor.module/tests/` |
||
319 | * by pattern `<class>test.php` and loading modules of tests. |
||
320 | * |
||
321 | * @throws ConfigurationException |
||
322 | */ |
||
323 | public function autoloadTests() |
||
324 | { |
||
325 | if ($this->getConfiguration() === null) { |
||
326 | $this->loadConfiguration(); |
||
327 | } |
||
328 | |||
329 | $this->initializeBitrix(); |
||
330 | |||
331 | spl_autoload_register(function ($className) { |
||
332 | $file = ltrim($className, "\\"); |
||
333 | $file = strtr($file, Loader::ALPHA_UPPER, Loader::ALPHA_LOWER); |
||
334 | $file = str_replace('\\', '/', $file); |
||
335 | |||
336 | if (substr($file, -5) === 'table') { |
||
337 | $file = substr($file, 0, -5); |
||
338 | } |
||
339 | |||
340 | $arFile = explode('/', $file); |
||
341 | |||
342 | if (preg_match("#[^\\\\/a-zA-Z0-9_]#", $file)) { |
||
343 | return false; |
||
344 | } elseif ($arFile[0] === 'bitrix') { |
||
345 | return false; |
||
346 | } elseif ($arFile[2] !== 'tests') { |
||
347 | return false; |
||
348 | } |
||
349 | |||
350 | $module = array_shift($arFile) . '.' . array_shift($arFile); |
||
351 | |||
352 | if (!Loader::includeModule($module)) { |
||
353 | return false; |
||
354 | } |
||
355 | |||
356 | $path = getLocalPath('/modules/' . $module . '/' . implode('/', $arFile) . '.php'); |
||
357 | |||
358 | if ($path !== false) { |
||
359 | include_once $this->getDocumentRoot() . $path; |
||
360 | } |
||
361 | }); |
||
362 | } |
||
363 | |||
364 | /** |
||
365 | * Gets root directory from which are running Console Jedi. |
||
366 | * |
||
367 | * @return string |
||
368 | */ |
||
369 | public function getRoot() |
||
370 | { |
||
371 | return getcwd(); |
||
372 | } |
||
373 | |||
374 | /** |
||
375 | * Sets path to the document root of site. |
||
376 | * |
||
377 | * @param string $dir Path to document root. |
||
378 | */ |
||
379 | public function setDocumentRoot($dir) |
||
0 ignored issues
–
show
setDocumentRoot uses the super-global variable $_SERVER which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
380 | { |
||
381 | $_SERVER['DOCUMENT_ROOT'] = $this->documentRoot = $dir; |
||
382 | } |
||
383 | |||
384 | /** |
||
385 | * Gets document root of site. |
||
386 | * |
||
387 | * @return null|string |
||
388 | */ |
||
389 | public function getDocumentRoot() |
||
390 | { |
||
391 | return $this->documentRoot; |
||
392 | } |
||
393 | } |
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:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.