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\Module; |
||
8 | |||
9 | use Bitrix\Main\Config\Option; |
||
10 | use Bitrix\Main\ModuleManager; |
||
11 | use Notamedia\ConsoleJedi\Application\Exception\BitrixException; |
||
12 | use Symfony\Component\Filesystem\Filesystem; |
||
13 | |||
14 | /** |
||
15 | * Module entity. |
||
16 | * |
||
17 | * @author Marat Shamshutdinov <[email protected]> |
||
18 | */ |
||
19 | class Module |
||
20 | { |
||
21 | /** |
||
22 | * @var string |
||
23 | */ |
||
24 | private $name; |
||
25 | /** |
||
26 | * @var \CModule |
||
27 | */ |
||
28 | private $object; |
||
29 | /** |
||
30 | * @var bool |
||
31 | */ |
||
32 | private $beta = false; |
||
33 | |||
34 | /** |
||
35 | * @param string $moduleName |
||
36 | */ |
||
37 | public function __construct($moduleName) |
||
38 | { |
||
39 | $this->name = $this->normalizeName($moduleName); |
||
40 | } |
||
41 | |||
42 | /** |
||
43 | * @param string $moduleName |
||
44 | * @return string |
||
45 | */ |
||
46 | protected function normalizeName($moduleName) |
||
47 | { |
||
48 | return preg_replace("/[^a-zA-Z0-9_.]+/i", "", trim($moduleName)); |
||
49 | } |
||
50 | |||
51 | /** |
||
52 | * @return \CModule |
||
53 | */ |
||
54 | protected function &getObject() |
||
55 | { |
||
56 | if (!isset($this->object)) { |
||
57 | $this->object = \CModule::CreateModuleObject($this->name); |
||
58 | } |
||
59 | |||
60 | if (!is_object($this->object) || !($this->object instanceof \CModule)) { |
||
0 ignored issues
–
show
|
|||
61 | unset($this->object); |
||
62 | throw new Exception\ModuleNotFoundException('Module not found or incorrect', $this->name); |
||
63 | } |
||
64 | |||
65 | return $this->object; |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * Checks for module and module object existence. |
||
70 | * |
||
71 | * @return bool |
||
72 | */ |
||
73 | public function exist() |
||
74 | { |
||
75 | try { |
||
76 | $this->getObject(); |
||
77 | } catch (Exception\ModuleNotFoundException $e) { |
||
78 | return false; |
||
79 | } |
||
80 | |||
81 | return true; |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * Check if module exists and installed |
||
86 | * |
||
87 | * @return bool |
||
88 | */ |
||
89 | public function isRegistered() |
||
90 | { |
||
91 | return ModuleManager::isModuleInstalled($this->name) && $this->exist(); |
||
92 | } |
||
93 | |||
94 | /** |
||
95 | * @return bool true for marketplace modules, false for kernel modules |
||
96 | */ |
||
97 | public function isThirdParty() |
||
98 | { |
||
99 | return strpos($this->name, '.') !== false; |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * Install module. |
||
104 | * |
||
105 | * @throws Exception\ModuleException |
||
106 | * @throws BitrixException |
||
107 | */ |
||
108 | View Code Duplication | public function register() |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
109 | { |
||
110 | if (!$this->isRegistered()) { |
||
111 | $moduleObject =& $this->getObject(); |
||
112 | |||
113 | /** |
||
114 | * It's important to check if module class defines InstallDB method (it must register module) |
||
115 | * Thus absent InstallDB indicates that the module does not support automatic installation |
||
116 | */ |
||
117 | if ((new \ReflectionClass($moduleObject))->getMethod('InstallDB')->class !== get_class($moduleObject)) { |
||
118 | throw new Exception\ModuleInstallException( |
||
119 | 'Missing InstallDB method. This module does not support automatic installation', |
||
120 | $this->name |
||
121 | ); |
||
122 | } |
||
123 | |||
124 | if (!$moduleObject->InstallDB() && BitrixException::hasException()) { |
||
125 | throw new Exception\ModuleInstallException( |
||
126 | get_class($moduleObject) . '::InstallDB() returned false', |
||
127 | $this->name |
||
128 | ); |
||
129 | } |
||
130 | |||
131 | $moduleObject->InstallEvents(); |
||
132 | |||
133 | /** @noinspection PhpVoidFunctionResultUsedInspection */ |
||
134 | if (!$moduleObject->InstallFiles() && BitrixException::hasException()) { |
||
135 | throw new Exception\ModuleInstallException( |
||
136 | get_class($moduleObject) . '::InstallFiles() returned false', |
||
137 | $this->name |
||
138 | ); |
||
139 | } |
||
140 | |||
141 | if (!$this->isRegistered()) { |
||
142 | throw new Exception\ModuleInstallException( |
||
143 | 'Module was not registered. Probably it does not support automatic installation.', |
||
144 | $this->name |
||
145 | ); |
||
146 | } |
||
147 | } |
||
148 | |||
149 | return $this; |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Download module from Marketplace. |
||
154 | * |
||
155 | * @return $this |
||
156 | */ |
||
157 | public function load() |
||
0 ignored issues
–
show
load 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);
}
}
![]() |
|||
158 | { |
||
159 | if (!$this->isRegistered()) { |
||
160 | if (!$this->exist()) { |
||
161 | require_once($_SERVER["DOCUMENT_ROOT"] . '/bitrix/modules/main/classes/general/update_client_partner.php'); |
||
162 | |||
163 | if (!\CUpdateClientPartner::LoadModuleNoDemand( |
||
164 | $this->getName(), |
||
165 | $strError, |
||
0 ignored issues
–
show
|
|||
166 | $this->isBeta() ? 'N' : 'Y', |
||
167 | LANGUAGE_ID) |
||
168 | ) { |
||
169 | throw new Exception\ModuleLoadException($strError, $this->getName()); |
||
170 | } |
||
171 | } |
||
172 | } |
||
173 | |||
174 | return $this; |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Uninstall module. |
||
179 | * |
||
180 | * @throws Exception\ModuleException |
||
181 | * @throws BitrixException |
||
182 | */ |
||
183 | View Code Duplication | public function unRegister() |
|
0 ignored issues
–
show
This method seems to be duplicated in 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. ![]() |
|||
184 | { |
||
185 | $moduleObject = $this->getObject(); |
||
186 | |||
187 | if ($this->isRegistered()) { |
||
188 | /** |
||
189 | * It's important to check if module class defines UnInstallDB method (it should unregister module) |
||
190 | * Thus absent UnInstallDB indicates that the module does not support automatic uninstallation |
||
191 | */ |
||
192 | if ((new \ReflectionClass($moduleObject))->getMethod('UnInstallDB')->class !== get_class($moduleObject)) { |
||
193 | throw new Exception\ModuleUninstallException( |
||
194 | 'Missing UnInstallDB method. This module does not support automatic uninstallation', |
||
195 | $this->name |
||
196 | ); |
||
197 | } |
||
198 | |||
199 | /** @noinspection PhpVoidFunctionResultUsedInspection */ |
||
200 | if (!$moduleObject->UnInstallFiles() && BitrixException::hasException()) { |
||
201 | throw new Exception\ModuleUninstallException( |
||
202 | get_class($moduleObject) . '::UnInstallFiles() returned false', |
||
203 | $this->name |
||
204 | ); |
||
205 | } |
||
206 | |||
207 | $moduleObject->UnInstallEvents(); |
||
208 | |||
209 | /** @noinspection PhpVoidFunctionResultUsedInspection */ |
||
210 | if (!$moduleObject->UnInstallDB() && BitrixException::hasException()) { |
||
211 | throw new Exception\ModuleUninstallException( |
||
212 | get_class($moduleObject) . '::UnInstallFiles() returned false', |
||
213 | $this->name |
||
214 | ); |
||
215 | } |
||
216 | |||
217 | if ($this->isRegistered()) { |
||
218 | throw new Exception\ModuleUninstallException('Module was not unregistered', $this->name); |
||
219 | } |
||
220 | } |
||
221 | |||
222 | return $this; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Uninstall and remove module directory. |
||
227 | */ |
||
228 | public function remove() |
||
0 ignored issues
–
show
remove 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);
}
}
![]() |
|||
229 | { |
||
230 | if ($this->isRegistered()) { |
||
231 | $this->unRegister(); |
||
232 | } |
||
233 | |||
234 | $path = getLocalPath('modules/' . $this->getName()); |
||
235 | |||
236 | if ($path) { |
||
237 | (new Filesystem())->remove($_SERVER['DOCUMENT_ROOT'] . $path); |
||
238 | } |
||
239 | |||
240 | unset($this->object); |
||
241 | |||
242 | return $this; |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * Update module. |
||
247 | * |
||
248 | * It must be called repeatedly until the method returns false. |
||
249 | * After each call php must be restarted (new process created) to update module class and function definitions. |
||
250 | * |
||
251 | * @param array $modulesUpdated [optional] |
||
252 | * @return bool |
||
253 | */ |
||
254 | public function update(&$modulesUpdated = null) |
||
0 ignored issues
–
show
update 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);
}
}
![]() |
|||
255 | { |
||
256 | require_once($_SERVER["DOCUMENT_ROOT"] . '/bitrix/modules/main/classes/general/update_client_partner.php'); |
||
257 | |||
258 | if (!$this->isThirdParty()) { |
||
259 | throw new Exception\ModuleUpdateException('Kernel module updates are currently not supported.', |
||
260 | $this->getName()); |
||
261 | } |
||
262 | |||
263 | // ensures module existence |
||
264 | $this->getObject(); |
||
265 | |||
266 | $errorMessage = $updateDescription = null; |
||
267 | $loadResult = \CUpdateClientPartner::LoadModulesUpdates( |
||
268 | $errorMessage, |
||
269 | $updateDescription, |
||
270 | LANGUAGE_ID, |
||
271 | $this->isBeta() ? 'N' : 'Y', |
||
272 | [$this->getName()], |
||
273 | true |
||
274 | ); |
||
275 | switch ($loadResult) { |
||
276 | // archive loaded |
||
277 | case "S": |
||
278 | return $this->update($modulesUpdated); |
||
279 | |||
280 | // error |
||
281 | case "E": |
||
282 | throw new Exception\ModuleUpdateException($errorMessage, $this->getName()); |
||
283 | |||
284 | // finished installing updates |
||
285 | case "F": |
||
286 | return false; |
||
287 | |||
288 | // need to process loaded update |
||
289 | case 'U': |
||
290 | break; |
||
291 | } |
||
292 | |||
293 | /** @var string Temp directory with update files */ |
||
294 | $updateDir = null; |
||
295 | |||
296 | if (!\CUpdateClientPartner::UnGzipArchive($updateDir, $errorMessage, true)) { |
||
297 | throw new Exception\ModuleUpdateException('[CL02] UnGzipArchive failed. ' . $errorMessage, |
||
298 | $this->getName()); |
||
299 | } |
||
300 | |||
301 | $this->validateUpdate($updateDir); |
||
302 | |||
303 | if (isset($updateDescription["DATA"]["#"]["NOUPDATES"])) { |
||
304 | \CUpdateClientPartner::ClearUpdateFolder($_SERVER["DOCUMENT_ROOT"] . "/bitrix/updates/" . $updateDir); |
||
305 | return false; |
||
306 | } |
||
307 | |||
308 | $modulesUpdated = $updateDescr = []; |
||
309 | if (isset($updateDescription["DATA"]["#"]["ITEM"])) { |
||
310 | foreach ($updateDescription["DATA"]["#"]["ITEM"] as $moduleInfo) { |
||
311 | $modulesUpdated[$moduleInfo["@"]["NAME"]] = $moduleInfo["@"]["VALUE"]; |
||
312 | $updateDescr[$moduleInfo["@"]["NAME"]] = $moduleInfo["@"]["DESCR"]; |
||
313 | } |
||
314 | } |
||
315 | |||
316 | if (\CUpdateClientPartner::UpdateStepModules($updateDir, $errorMessage)) { |
||
317 | foreach ($modulesUpdated as $key => $value) { |
||
318 | if (Option::set('main', 'event_log_marketplace', "Y") === "Y") { |
||
319 | \CEventLog::Log("INFO", "MP_MODULE_DOWNLOADED", "main", $key, $value); |
||
320 | } |
||
321 | } |
||
322 | } else { |
||
323 | throw new Exception\ModuleUpdateException('[CL04] UpdateStepModules failed. ' . $errorMessage, |
||
324 | $this->getName()); |
||
325 | } |
||
326 | |||
327 | return true; |
||
328 | } |
||
329 | |||
330 | /** |
||
331 | * Check update files. |
||
332 | * |
||
333 | * @param string $updateDir |
||
334 | */ |
||
335 | protected function validateUpdate($updateDir) |
||
336 | { |
||
337 | $errorMessage = null; |
||
338 | if (!\CUpdateClientPartner::CheckUpdatability($updateDir, $errorMessage)) { |
||
339 | throw new Exception\ModuleUpdateException('[CL03] CheckUpdatability failed. ' . $errorMessage, |
||
340 | $this->getName()); |
||
341 | } |
||
342 | |||
343 | if (isset($updateDescription["DATA"]["#"]["ERROR"])) { |
||
0 ignored issues
–
show
The variable
$updateDescription seems to never exist, and therefore isset should always return false . Did you maybe rename this variable?
This check looks for calls to This is most likely caused by the renaming of a variable or the removal of a function/method parameter. ![]() |
|||
344 | $errorMessage = ""; |
||
345 | foreach ($updateDescription["DATA"]["#"]["ERROR"] as $errorDescription) { |
||
346 | $errorMessage .= "[" . $errorDescription["@"]["TYPE"] . "] " . $errorDescription["#"]; |
||
347 | } |
||
348 | throw new Exception\ModuleUpdateException($errorMessage, $this->getName()); |
||
349 | } |
||
350 | } |
||
351 | |||
352 | /** |
||
353 | * Returns module name. |
||
354 | * |
||
355 | * @return string |
||
356 | */ |
||
357 | public function getName() |
||
358 | { |
||
359 | return $this->name; |
||
360 | } |
||
361 | |||
362 | /** |
||
363 | * Beta releases allowed? |
||
364 | * |
||
365 | * @return boolean |
||
366 | */ |
||
367 | public function isBeta() |
||
368 | { |
||
369 | return $this->beta; |
||
370 | } |
||
371 | |||
372 | /** |
||
373 | * Set beta releases installation. |
||
374 | * |
||
375 | * @param boolean $beta |
||
376 | */ |
||
377 | public function setBeta($beta = true) |
||
378 | { |
||
379 | $this->beta = $beta; |
||
380 | } |
||
381 | |||
382 | public function getVersion() |
||
383 | { |
||
384 | return $this->getObject()->MODULE_VERSION; |
||
385 | } |
||
386 | } |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.