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 | /* |
||
4 | * This file is part of Bowerphp. |
||
5 | * |
||
6 | * (c) Massimiliano Arione <[email protected]> |
||
7 | * |
||
8 | * For the full copyright and license information, please view the LICENSE |
||
9 | * file that was distributed with this source code. |
||
10 | */ |
||
11 | |||
12 | namespace Bowerphp; |
||
13 | |||
14 | use Bowerphp\Config\ConfigInterface; |
||
15 | use Bowerphp\Installer\InstallerInterface; |
||
16 | use Bowerphp\Output\BowerphpConsoleOutput; |
||
17 | use Bowerphp\Package\Package; |
||
18 | use Bowerphp\Package\PackageInterface; |
||
19 | use Bowerphp\Repository\RepositoryInterface; |
||
20 | use Bowerphp\Util\Filesystem; |
||
21 | use Github\Client; |
||
22 | use Guzzle\Http\Exception\RequestException; |
||
23 | use InvalidArgumentException; |
||
24 | use RuntimeException; |
||
25 | use Symfony\Component\Finder\Finder; |
||
26 | use vierbergenlars\SemVer\expression; |
||
27 | use vierbergenlars\SemVer\version; |
||
28 | |||
29 | /** |
||
30 | * Main class |
||
31 | */ |
||
32 | class Bowerphp |
||
0 ignored issues
–
show
|
|||
33 | { |
||
34 | protected $config; |
||
35 | |||
36 | protected $filesystem; |
||
37 | |||
38 | protected $githubClient; |
||
39 | |||
40 | protected $repository; |
||
41 | |||
42 | protected $output; |
||
43 | |||
44 | /** |
||
45 | * @param ConfigInterface $config |
||
46 | * @param Filesystem $filesystem |
||
47 | * @param Client $githubClient |
||
48 | * @param RepositoryInterface $repository |
||
49 | * @param BowerphpConsoleOutput $output |
||
50 | */ |
||
51 | public function __construct( |
||
52 | ConfigInterface $config, |
||
53 | Filesystem $filesystem, |
||
54 | Client $githubClient, |
||
55 | RepositoryInterface $repository, |
||
56 | BowerphpConsoleOutput $output |
||
57 | ) { |
||
58 | $this->config = $config; |
||
59 | $this->filesystem = $filesystem; |
||
60 | $this->githubClient = $githubClient; |
||
61 | $this->repository = $repository; |
||
62 | $this->output = $output; |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * Init bower.json |
||
67 | * |
||
68 | * @param array $params |
||
69 | */ |
||
70 | public function init(array $params) |
||
71 | { |
||
72 | if ($this->config->bowerFileExists()) { |
||
73 | $bowerJson = $this->config->getBowerFileContent(); |
||
74 | $this->config->setSaveToBowerJsonFile(); |
||
75 | $this->config->updateBowerJsonFile2($bowerJson, $params); |
||
76 | } else { |
||
77 | $this->config->initBowerJsonFile($params); |
||
78 | } |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Install a single package |
||
83 | * |
||
84 | * @param PackageInterface $package |
||
85 | * @param InstallerInterface $installer |
||
86 | * @param bool $isDependency |
||
87 | */ |
||
88 | public function installPackage(PackageInterface $package, InstallerInterface $installer, $isDependency = false) |
||
89 | { |
||
90 | if (false !== strpos($package->getName(), 'github')) { |
||
91 | // install from a github endpoint |
||
92 | $name = basename($package->getName(), '.git'); |
||
93 | $repoUrl = $package->getName(); |
||
94 | $package = new Package($name, $package->getRequiredVersion()); |
||
95 | $this->repository->setUrl($repoUrl)->setHttpClient($this->githubClient); |
||
96 | $package->setRepository($this->repository); |
||
97 | $packageTag = $this->repository->findPackage($package->getRequiredVersion()); |
||
98 | if (is_null($packageTag)) { |
||
99 | throw new RuntimeException(sprintf('Cannot find package %s version %s.', $package->getName(), $package->getRequiredVersion())); |
||
100 | } |
||
101 | } else { |
||
102 | $packageTag = $this->getPackageTag($package, true); |
||
103 | $package->setRepository($this->repository); |
||
104 | } |
||
105 | |||
106 | $package->setVersion($packageTag); |
||
107 | |||
108 | $this->updateBowerFile($package, $isDependency); |
||
109 | |||
110 | // if package is already installed, match current version with latest available version |
||
111 | if ($this->isPackageInstalled($package)) { |
||
112 | $this->output->writelnInfoPackage($package, 'validate', sprintf('%s against %s#%s', $packageTag, $package->getName(), $package->getRequiredVersion())); |
||
113 | $packageBower = $this->config->getPackageBowerFileContent($package); |
||
114 | if ($packageTag == $packageBower['version']) { |
||
115 | // if version is fully matching, there's no need to install |
||
116 | return; |
||
117 | } |
||
118 | } |
||
119 | |||
120 | $this->cachePackage($package); |
||
121 | |||
122 | $this->output->writelnInstalledPackage($package); |
||
123 | $installer->install($package); |
||
124 | |||
125 | $overrides = $this->config->getOverrideFor($package->getName()); |
||
126 | if (array_key_exists('dependencies', $overrides)) { |
||
127 | $dependencies = $overrides['dependencies']; |
||
128 | } else { |
||
129 | $dependencies = $package->getRequires(); |
||
130 | } |
||
131 | if (!empty($dependencies)) { |
||
132 | foreach ($dependencies as $name => $version) { |
||
133 | $depPackage = new Package($name, $version); |
||
134 | if (!$this->isPackageInstalled($depPackage)) { |
||
135 | $this->installPackage($depPackage, $installer, true); |
||
136 | } elseif ($this->isNeedUpdate($depPackage)) { |
||
137 | $this->updatePackage($depPackage, $installer); |
||
138 | } |
||
139 | } |
||
140 | } |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * Install all dependencies |
||
145 | * |
||
146 | * @param InstallerInterface $installer |
||
147 | */ |
||
148 | public function installDependencies(InstallerInterface $installer) |
||
149 | { |
||
150 | $decode = $this->config->getBowerFileContent(); |
||
151 | if (!empty($decode['dependencies'])) { |
||
152 | foreach ($decode['dependencies'] as $name => $requiredVersion) { |
||
153 | if (false !== strpos($requiredVersion, 'github')) { |
||
154 | list($name, $requiredVersion) = explode('#', $requiredVersion); |
||
155 | } |
||
156 | $package = new Package($name, $requiredVersion); |
||
157 | $this->installPackage($package, $installer, true); |
||
158 | } |
||
159 | } |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * Update a single package |
||
164 | * |
||
165 | * @param PackageInterface $package |
||
166 | * @param InstallerInterface $installer |
||
167 | */ |
||
168 | public function updatePackage(PackageInterface $package, InstallerInterface $installer) |
||
0 ignored issues
–
show
This operation has 800 execution paths which exceeds the configured maximum of 200.
A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods. You can also find more information in the “Code” section of your repository. ![]() |
|||
169 | { |
||
170 | if (!$this->isPackageInstalled($package)) { |
||
171 | throw new RuntimeException(sprintf('Package %s is not installed.', $package->getName())); |
||
172 | } |
||
173 | if (is_null($package->getRequiredVersion())) { |
||
174 | $decode = $this->config->getBowerFileContent(); |
||
175 | if (empty($decode['dependencies']) || empty($decode['dependencies'][$package->getName()])) { |
||
176 | throw new InvalidArgumentException(sprintf('Package %s not found in bower.json', $package->getName())); |
||
177 | } |
||
178 | $package->setRequiredVersion($decode['dependencies'][$package->getName()]); |
||
179 | } |
||
180 | |||
181 | $bower = $this->config->getPackageBowerFileContent($package); |
||
182 | $package->setInfo($bower); |
||
183 | $package->setVersion($bower['version']); |
||
184 | $package->setRequires(isset($bower['dependencies']) ? $bower['dependencies'] : null); |
||
185 | |||
186 | $packageTag = $this->getPackageTag($package); |
||
187 | $this->output->writelnInfoPackage($package, 'validate', sprintf('%s against %s#%s', $packageTag, $package->getName(), $package->getRequiredVersion())); |
||
188 | |||
189 | $package->setRepository($this->repository); |
||
190 | if ($packageTag == $package->getVersion()) { |
||
191 | // if version is fully matching, there's no need to update |
||
192 | return; |
||
193 | } |
||
194 | $package->setVersion($packageTag); |
||
195 | |||
196 | $this->cachePackage($package); |
||
197 | |||
198 | $this->output->writelnUpdatingPackage($package); |
||
199 | $installer->update($package); |
||
200 | |||
201 | $overrides = $this->config->getOverrideFor($package->getName()); |
||
202 | if (array_key_exists('dependencies', $overrides)) { |
||
203 | $dependencies = $overrides['dependencies']; |
||
204 | } else { |
||
205 | $dependencies = $package->getRequires(); |
||
206 | } |
||
207 | if (!empty($dependencies)) { |
||
208 | foreach ($dependencies as $name => $requiredVersion) { |
||
209 | $depPackage = new Package($name, $requiredVersion); |
||
210 | if (!$this->isPackageInstalled($depPackage)) { |
||
211 | $this->installPackage($depPackage, $installer, true); |
||
212 | } elseif ($this->isNeedUpdate($depPackage)) { |
||
213 | $this->updatePackage($depPackage, $installer); |
||
214 | } |
||
215 | } |
||
216 | } |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Update all dependencies |
||
221 | * |
||
222 | * @param InstallerInterface $installer |
||
223 | */ |
||
224 | public function updatePackages(InstallerInterface $installer) |
||
225 | { |
||
226 | $decode = $this->config->getBowerFileContent(); |
||
227 | if (!empty($decode['dependencies'])) { |
||
228 | foreach ($decode['dependencies'] as $packageName => $requiredVersion) { |
||
229 | $this->updatePackage(new Package($packageName, $requiredVersion), $installer); |
||
230 | } |
||
231 | } |
||
232 | } |
||
233 | |||
234 | /** |
||
235 | * @param PackageInterface $package |
||
236 | * @param string $info |
||
237 | * @return mixed |
||
238 | */ |
||
239 | public function getPackageInfo(PackageInterface $package, $info = 'url') |
||
240 | { |
||
241 | $decode = $this->lookupPackage($package->getName()); |
||
242 | |||
243 | $this->repository->setHttpClient($this->githubClient); |
||
244 | |||
245 | if ('url' == $info) { |
||
246 | $this->repository->setUrl($decode['url'], false); |
||
247 | |||
248 | return $this->repository->getUrl(); |
||
249 | } |
||
250 | |||
251 | if ('versions' == $info) { |
||
252 | $tags = $this->repository->getTags(); |
||
253 | usort($tags, function ($a, $b) { |
||
0 ignored issues
–
show
|
|||
254 | return version_compare($b, $a); |
||
255 | }); |
||
256 | |||
257 | return $tags; |
||
258 | } |
||
259 | |||
260 | throw new RuntimeException(sprintf('Unsupported info option "%s".', $info)); |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * @param string $name |
||
265 | * @return array |
||
266 | */ |
||
267 | public function lookupPackage($name) |
||
268 | { |
||
269 | return $this->findPackage($name); |
||
270 | } |
||
271 | |||
272 | /** |
||
273 | * @param PackageInterface $package |
||
274 | * @return string |
||
275 | */ |
||
276 | public function getPackageBowerFile(PackageInterface $package) |
||
277 | { |
||
278 | $this->repository->setHttpClient($this->githubClient); |
||
279 | $lookupPackage = $this->lookupPackage($package->getName()); |
||
280 | $this->repository->setUrl($lookupPackage['url'], false); |
||
281 | $tag = $this->repository->findPackage($package->getRequiredVersion()); |
||
282 | |||
283 | return $this->repository->getBower($tag, true, $lookupPackage['url']); |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Uninstall a single package |
||
288 | * |
||
289 | * @param PackageInterface $package |
||
290 | * @param InstallerInterface $installer |
||
291 | */ |
||
292 | public function uninstallPackage(PackageInterface $package, InstallerInterface $installer) |
||
293 | { |
||
294 | if (!$this->isPackageInstalled($package)) { |
||
295 | throw new RuntimeException(sprintf('Package %s is not installed.', $package->getName())); |
||
296 | } |
||
297 | $installer->uninstall($package); |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * Search packages by name |
||
302 | * |
||
303 | * @param string $name |
||
304 | * @return array |
||
305 | */ |
||
306 | public function searchPackages($name) |
||
307 | { |
||
308 | try { |
||
309 | $url = $this->config->getBasePackagesUrl() . 'search/' . $name; |
||
310 | $response = $this->githubClient->getHttpClient()->get($url); |
||
311 | |||
312 | return json_decode($response->getBody(true), true); |
||
313 | } catch (RequestException $e) { |
||
314 | throw new RuntimeException(sprintf('Cannot get package list from %s.', str_replace('/packages/', '', $this->config->getBasePackagesUrl()))); |
||
315 | } |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * Get a list of installed packages |
||
320 | * |
||
321 | * @param InstallerInterface $installer |
||
322 | * @param Finder $finder |
||
323 | * @return array |
||
324 | */ |
||
325 | public function getInstalledPackages(InstallerInterface $installer, Finder $finder) |
||
326 | { |
||
327 | return $installer->getInstalled($finder); |
||
328 | } |
||
329 | |||
330 | /** |
||
331 | * Check if package is installed |
||
332 | * |
||
333 | * @param PackageInterface $package |
||
334 | * @return bool |
||
335 | */ |
||
336 | public function isPackageInstalled(PackageInterface $package) |
||
337 | { |
||
338 | return $this->filesystem->exists($this->config->getInstallDir() . '/' . $package->getName() . '/.bower.json'); |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * @param PackageInterface $package |
||
343 | * @param bool $checkInstall |
||
344 | * |
||
345 | * @return bool |
||
346 | */ |
||
347 | public function isPackageExtraneous(PackageInterface $package, $checkInstall = false) |
||
0 ignored issues
–
show
This operation has 216 execution paths which exceeds the configured maximum of 200.
A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods. You can also find more information in the “Code” section of your repository. ![]() |
|||
348 | { |
||
349 | if ($checkInstall && !$this->isPackageInstalled($package)) { |
||
350 | return false; |
||
351 | } |
||
352 | |||
353 | try { |
||
354 | $bower = $this->config->getBowerFileContent(); |
||
355 | } catch (RuntimeException $e) { // no bower.json file, package is extraneous |
||
356 | return true; |
||
357 | } |
||
358 | if (!isset($bower['dependencies'])) { |
||
359 | return true; |
||
360 | } |
||
361 | // package is a direct dependencies |
||
362 | if (isset($bower['dependencies'][$package->getName()])) { |
||
363 | return false; |
||
364 | } |
||
365 | // look for dependencies of dependencies |
||
366 | foreach ($bower['dependencies'] as $name => $version) { |
||
367 | $dotBowerJson = $this->filesystem->read($this->config->getInstallDir() . '/' . $name . '/.bower.json'); |
||
368 | $depBower = json_decode($dotBowerJson, true); |
||
369 | if (isset($depBower['dependencies'][$package->getName()])) { |
||
370 | return false; |
||
371 | } |
||
372 | // look for dependencies of dependencies of dependencies |
||
373 | if (isset($depBower['dependencies'])) { |
||
374 | foreach ($depBower['dependencies'] as $name1 => $version1) { |
||
375 | $dotBowerJson = $this->filesystem->read($this->config->getInstallDir() . '/' . $name1 . '/.bower.json'); |
||
376 | $depDepBower = json_decode($dotBowerJson, true); |
||
377 | if (isset($depDepBower['dependencies'][$package->getName()])) { |
||
378 | return false; |
||
379 | } |
||
380 | } |
||
381 | } |
||
382 | } |
||
383 | |||
384 | return true; |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * @param array $params |
||
389 | * @return array |
||
390 | */ |
||
391 | protected function createAClearBowerFile(array $params) |
||
392 | { |
||
393 | $authors = ['Beelab <[email protected]>']; |
||
394 | if (!empty($params['author'])) { |
||
395 | $authors[] = $params['author']; |
||
396 | } |
||
397 | $structure = [ |
||
398 | 'name' => $params['name'], |
||
399 | 'authors' => $authors, |
||
400 | 'private' => true, |
||
401 | 'dependencies' => new \StdClass(), |
||
402 | ]; |
||
403 | |||
404 | return $structure; |
||
405 | } |
||
406 | |||
407 | /** |
||
408 | * @param PackageInterface $package |
||
409 | * @param bool $setInfo |
||
410 | * @return string |
||
411 | */ |
||
412 | protected function getPackageTag(PackageInterface $package, $setInfo = false) |
||
413 | { |
||
414 | $decode = $this->findPackage($package->getName()); |
||
415 | // open package repository |
||
416 | $repoUrl = $decode['url']; |
||
417 | $this->repository->setUrl($repoUrl)->setHttpClient($this->githubClient); |
||
418 | $packageTag = $this->repository->findPackage($package->getRequiredVersion()); |
||
419 | if (is_null($packageTag)) { |
||
420 | throw new RuntimeException(sprintf('Cannot find package %s version %s.', $package->getName(), $package->getRequiredVersion())); |
||
421 | } |
||
422 | $bowerJson = $this->repository->getBower($packageTag); |
||
423 | $bower = json_decode($bowerJson, true); |
||
424 | if (!is_array($bower)) { |
||
425 | throw new RuntimeException(sprintf('Invalid bower.json found in package %s: %s.', $package->getName(), $bowerJson)); |
||
426 | } |
||
427 | if ($setInfo) { |
||
428 | $package->setInfo($bower); |
||
429 | } |
||
430 | |||
431 | return $packageTag; |
||
432 | } |
||
433 | |||
434 | /** |
||
435 | * @param string $name |
||
436 | * @return array |
||
437 | */ |
||
438 | protected function findPackage($name) |
||
439 | { |
||
440 | try { |
||
441 | $response = $this->githubClient->getHttpClient()->get($this->config->getBasePackagesUrl() . urlencode($name)); |
||
442 | } catch (RuntimeException $e) { |
||
443 | throw new RuntimeException(sprintf('Cannot fetch registry info for package %s from search registry (%s).', $name, $e->getMessage())); |
||
444 | } |
||
445 | $packageInfo = json_decode($response->getBody(true), true); |
||
446 | if (!is_array($packageInfo) || empty($packageInfo['url'])) { |
||
447 | throw new RuntimeException(sprintf('Registry info for package %s has malformed json or is missing "url".', $name)); |
||
448 | } |
||
449 | |||
450 | return $packageInfo; |
||
451 | } |
||
452 | |||
453 | /** |
||
454 | * @param PackageInterface $package |
||
455 | */ |
||
456 | private function cachePackage(PackageInterface $package) |
||
457 | { |
||
458 | $this->output->writelnInfoPackage($package, 'download'); |
||
459 | |||
460 | // get release archive from repository |
||
461 | $file = $this->repository->getRelease(); |
||
462 | |||
463 | $tmpFileName = $this->config->getCacheDir() . '/tmp/' . $package->getName(); |
||
464 | $this->filesystem->write($tmpFileName, $file); |
||
465 | } |
||
466 | |||
467 | /** |
||
468 | * @param PackageInterface $package |
||
469 | * @param bool $isDependency |
||
470 | */ |
||
471 | private function updateBowerFile(PackageInterface $package, $isDependency = false) |
||
472 | { |
||
473 | if ($this->config->isSaveToBowerJsonFile() && !$isDependency) { |
||
474 | try { |
||
475 | $this->config->updateBowerJsonFile($package); |
||
476 | } catch (RuntimeException $e) { |
||
477 | $this->output->writelnNoBowerJsonFile(); |
||
478 | } |
||
479 | } |
||
480 | } |
||
481 | |||
482 | /** |
||
483 | * Update only if needed is greater version |
||
484 | * |
||
485 | * @param PackageInterface $package |
||
486 | * @return bool |
||
487 | */ |
||
488 | public function isNeedUpdate($package) |
||
489 | { |
||
490 | $packageBower = $this->config->getPackageBowerFileContent($package); |
||
491 | $semver = new version($packageBower['version']); |
||
492 | |||
493 | return !$semver->satisfies(new expression($package->getRequiredVersion())); |
||
494 | } |
||
495 | } |
||
496 |
The class complexity is the sum of the complexity of all methods. A very high value is usually an indication that your class does not follow the single reponsibility principle and does more than one job.
Some resources for further reading:
You can also find more detailed suggestions for refactoring in the “Code” section of your repository.