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 | namespace Bowerphp\Installer; |
||
4 | |||
5 | use Bowerphp\Config\ConfigInterface; |
||
6 | use Bowerphp\Package\Package; |
||
7 | use Bowerphp\Package\PackageInterface; |
||
8 | use Bowerphp\Util\Filesystem; |
||
9 | use Bowerphp\Util\ZipArchive; |
||
10 | use RuntimeException; |
||
11 | use Symfony\Component\Finder\Finder; |
||
12 | |||
13 | /** |
||
14 | * Package installation manager |
||
15 | */ |
||
16 | class Installer implements InstallerInterface |
||
17 | { |
||
18 | /** |
||
19 | * @var Filesystem |
||
20 | */ |
||
21 | protected $filesystem; |
||
22 | |||
23 | /** |
||
24 | * @var ZipArchive |
||
25 | */ |
||
26 | protected $zipArchive; |
||
27 | |||
28 | /** |
||
29 | * @var ConfigInterface |
||
30 | */ |
||
31 | protected $config; |
||
32 | |||
33 | /** |
||
34 | * Initializes library installer. |
||
35 | * |
||
36 | * @param Filesystem $filesystem |
||
37 | * @param ZipArchive $zipArchive |
||
38 | * @param ConfigInterface $config |
||
39 | */ |
||
40 | public function __construct(Filesystem $filesystem, ZipArchive $zipArchive, ConfigInterface $config) |
||
41 | { |
||
42 | $this->filesystem = $filesystem; |
||
43 | $this->zipArchive = $zipArchive; |
||
44 | $this->config = $config; |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * {@inheritdoc} |
||
49 | */ |
||
50 | public function install(PackageInterface $package) |
||
0 ignored issues
–
show
|
|||
51 | { |
||
52 | $tmpFileName = $this->config->getCacheDir() . '/tmp/' . $package->getName(); |
||
53 | if (true !== $this->zipArchive->open($tmpFileName)) { |
||
54 | throw new RuntimeException(sprintf('Unable to open zip file %s.', $tmpFileName)); |
||
55 | } |
||
56 | $dirName = trim($this->zipArchive->getNameIndex(0), '/'); |
||
57 | $info = $package->getInfo(); |
||
58 | $files = $this->filterZipFiles($this->zipArchive, isset($info['ignore']) ? $info['ignore'] : [], isset($info['main']) ? (array) $info['main'] : []); |
||
59 | foreach ($files as $i => $file) { |
||
60 | $stat = $this->zipArchive->statIndex($i); |
||
61 | $fileName = $this->config->getInstallDir() . '/' . str_replace($dirName, $package->getName(), $file); |
||
62 | if ('/' != substr($fileName, -1)) { |
||
63 | $fileContent = $this->zipArchive->getStream($file); |
||
64 | $this->filesystem->write($fileName, $fileContent); |
||
65 | $this->filesystem->touch($fileName, $stat['mtime']); |
||
66 | } |
||
67 | } |
||
68 | // adjust timestamp for directories |
||
69 | foreach ($files as $i => $file) { |
||
70 | $stat = $this->zipArchive->statIndex($i); |
||
71 | $fileName = $this->config->getInstallDir() . '/' . str_replace($dirName, $package->getName(), $file); |
||
72 | if (is_dir($fileName) && '/' == substr($fileName, -1)) { |
||
73 | $this->filesystem->touch($fileName, $stat['mtime']); |
||
74 | } |
||
75 | } |
||
76 | $this->zipArchive->close(); |
||
77 | |||
78 | // merge package info with bower.json contents |
||
79 | $bowerJsonPath = $this->config->getInstallDir() . '/' . $package->getName() . '/bower.json'; |
||
80 | if ($this->filesystem->exists($bowerJsonPath)) { |
||
81 | $bowerJson = $this->filesystem->read($bowerJsonPath); |
||
82 | $bower = json_decode($bowerJson, true); |
||
83 | $package->setInfo(array_merge($bower, $package->getInfo())); |
||
84 | } |
||
85 | |||
86 | // create .bower.json metadata file |
||
87 | // XXX we still need to add some other info |
||
88 | $dotBowerContent = array_merge($package->getInfo(), ['version' => $package->getVersion()]); |
||
89 | $dotBowerJson = str_replace('\/', '/', json_encode($dotBowerContent, JSON_PRETTY_PRINT)); |
||
90 | $this->filesystem->write($this->config->getInstallDir() . '/' . $package->getName() . '/.bower.json', $dotBowerJson); |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * {@inheritdoc} |
||
95 | */ |
||
96 | public function update(PackageInterface $package) |
||
97 | { |
||
98 | $this->install($package); |
||
99 | } |
||
100 | |||
101 | /** |
||
102 | * {@inheritdoc} |
||
103 | */ |
||
104 | public function uninstall(PackageInterface $package) |
||
105 | { |
||
106 | $this->removeDir($this->config->getInstallDir() . '/' . $package->getName()); |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * {@inheritdoc} |
||
111 | */ |
||
112 | public function getInstalled(Finder $finder) |
||
113 | { |
||
114 | $packages = []; |
||
115 | if (!$this->filesystem->exists($this->config->getInstallDir())) { |
||
116 | return $packages; |
||
117 | } |
||
118 | |||
119 | $directories = $finder->directories()->in($this->config->getInstallDir()); |
||
120 | |||
121 | foreach ($directories as $packageDirectory) { |
||
122 | if ($this->filesystem->exists($packageDirectory . '/.bower.json')) { |
||
123 | $bowerJson = $this->filesystem->read($packageDirectory . '/.bower.json'); |
||
124 | $bower = json_decode($bowerJson, true); |
||
125 | if (is_null($bower)) { |
||
126 | throw new RuntimeException(sprintf('Invalid content in .bower.json for package %s.', $packageDirectory)); |
||
127 | } |
||
128 | $packages[] = new Package($bower['name'], null, $bower['version'], isset($bower['dependencies']) ? $bower['dependencies'] : null, $bower); |
||
129 | } |
||
130 | } |
||
131 | |||
132 | return $packages; |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * {@inheritdoc} |
||
137 | */ |
||
138 | public function findDependentPackages(PackageInterface $package, Finder $finder) |
||
139 | { |
||
140 | $return = []; |
||
141 | $packages = $this->getInstalled($finder); |
||
142 | foreach ($packages as $installedPackage) { |
||
143 | $requires = $installedPackage->getRequires(); |
||
144 | if (isset($requires[$package->getName()])) { |
||
145 | $return[$requires[$package->getName()]] = $installedPackage; |
||
146 | } |
||
147 | } |
||
148 | |||
149 | return $return; |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Filter archive files based on an "ignore" list. |
||
154 | * |
||
155 | * @param ZipArchive $archive |
||
156 | * @param array $ignore |
||
157 | * @param array $force |
||
158 | * @return array |
||
159 | */ |
||
160 | protected function filterZipFiles(ZipArchive $archive, array $ignore = [], array $force = []) |
||
161 | { |
||
162 | $dirName = $archive->getNameIndex(0); |
||
163 | $return = []; |
||
164 | $numFiles = $archive->getNumFiles(); |
||
165 | for ($i = 0; $i < $numFiles; ++$i) { |
||
166 | $stat = $archive->statIndex($i); |
||
167 | $return[] = $stat['name']; |
||
168 | } |
||
169 | $that = $this; |
||
170 | $filter = array_filter($return, function ($var) use ($ignore, $force, $dirName, $that) { |
||
171 | return !$that->isIgnored($var, $ignore, $force, $dirName); |
||
172 | }); |
||
173 | |||
174 | return array_values($filter); |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * @param string $dir |
||
179 | */ |
||
180 | protected function removeDir($dir) |
||
181 | { |
||
182 | $this->filesystem->remove($dir); |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Check if a file should be ignored |
||
187 | * |
||
188 | * @param string $name file's name |
||
189 | * @param array $ignore list of ignores |
||
190 | * @param array $force list of files to force (do not ignore) |
||
191 | * @param string $dirName dir's name (to be removed from file's name) |
||
192 | * @return bool |
||
193 | */ |
||
194 | public function isIgnored($name, array $ignore, array $force, $dirName) |
||
0 ignored issues
–
show
This operation has 270 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. ![]() |
|||
195 | { |
||
196 | $vName = substr($name, strlen($dirName)); |
||
197 | if (in_array($vName, $force, true)) { |
||
198 | return false; |
||
199 | } |
||
200 | // first check if there is line that overrides other lines |
||
201 | foreach ($ignore as $pattern) { |
||
202 | if (0 !== strpos($pattern, '!')) { |
||
203 | continue; |
||
204 | } |
||
205 | $pattern = ltrim($pattern, '!'); |
||
206 | // the ! negates the line, otherwise the syntax is the same |
||
207 | if ($this->isIgnored($name, [$pattern], $force, $dirName)) { |
||
208 | return false; |
||
209 | } |
||
210 | } |
||
211 | foreach ($ignore as $pattern) { |
||
212 | if (false !== strpos($pattern, '**')) { |
||
213 | $pattern = str_replace('**', '*', $pattern); |
||
214 | //$pattern = str_replace('*/*', '*', $pattern); |
||
215 | if ('/' == substr($pattern, 0, 1)) { |
||
216 | $vName = '/' . $vName; |
||
217 | } |
||
218 | if ('.' == substr($vName, 0, 1)) { |
||
219 | $vName = '/' . $vName; |
||
220 | } |
||
221 | if (fnmatch($pattern, $vName, FNM_PATHNAME)) { |
||
222 | return true; |
||
223 | } elseif ('*/*' === $pattern && fnmatch('*', $vName, FNM_PATHNAME)) { |
||
224 | // this a special case, where a double asterisk must match also files in the root dir |
||
225 | return true; |
||
226 | } |
||
227 | } elseif ('/' == substr($pattern, -1)) { // trailing slash |
||
228 | if ('/' == substr($pattern, 0, 1)) { |
||
229 | $pattern = substr($pattern, 1); // remove possible starting slash |
||
230 | } |
||
231 | $escPattern = str_replace(['.', '*'], ['\.', '.*'], $pattern); |
||
232 | if (preg_match('#^' . $escPattern . '#', $vName) > 0) { |
||
233 | return true; |
||
234 | } |
||
235 | } elseif (false === strpos($pattern, '/')) { // no slash |
||
236 | $escPattern = str_replace(['.', '*'], ['\.', '.*'], $pattern); |
||
237 | if (preg_match('#^' . $escPattern . '#', $vName) > 0) { |
||
238 | return true; |
||
239 | } |
||
240 | } elseif ('/' == substr($pattern, 0, 1)) { // starting slash |
||
241 | $escPattern = str_replace(['.', '*'], ['\.', '.*'], $pattern); |
||
242 | if (preg_match('#^' . $escPattern . '#', '/' . $vName) > 0) { |
||
243 | return true; |
||
244 | } |
||
245 | } else { |
||
246 | $escPattern = str_replace(['.', '*'], ['\.', '.*'], $pattern); |
||
247 | if (preg_match('#^' . $escPattern . '#', $vName) > 0) { |
||
248 | return true; |
||
249 | } |
||
250 | } |
||
251 | } |
||
252 | |||
253 | return false; |
||
254 | } |
||
255 | } |
||
256 |
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.